Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

6719 Articles
article-image-unit-testing-angular-components-and-classes
Natasha Mathur
27 Aug 2018
12 min read
Save for later

Unit testing Angular components and classes [Tutorial]

Natasha Mathur
27 Aug 2018
12 min read
Testing (and more specifically, unit testing) is meant to be carried out by the developer as the project is being developed. In this article, we will see how to implement testing tools to perform proper unit testing for your application classes and components. This tutorial is an excerpt taken from the book Learning Angular (Second Edition) written by Christoffer Noring, Pablo Deeleman. When venturing into unit testing in Angular, it's important to know what major parts it consists of. In Angular these are: Jasmine, the testing framework Angular testing utilities Karma, a test runner for running unit tests, among other things Protractor, Angular's framework for E2E testing Configuration and setting up of Angular CLI In terms of configuration, when using the Angular CLI, you don't have to do anything to make it work. You can, as soon as you scaffold a project, run your first test and it will work.  The Angular CLI is using Karma as the test runner. What we need to know about Karma is that it uses a karma.conf.js file, a configuration file, in which a lot of things are specified, such as: The various plugins that enhance your test runner. Where to find the tests to run?  It should be said that there is usually a files property in this file specifying where to find the application and the tests. For the Angular CLI, however, this specification is found in another file called src/tscconfig-spec.json. Setup of your selected coverage tool, a tool that measures to what degree your tests cover the production code. Reporters report every executed test in a console window, to a browser, or through some other means. Browsers run your tests in: for example, Chrome or PhantomJS. Using the Angular CLI, you most likely won't need to change or edit this file yourself. It is good to know that it exists and what it does for you. Angular testing utilities The Angular testing utilities help to create a testing environment that makes writing tests for your various constructs really easy. It consists of the TestBed class and various helper functions, found under the @angular/core/testing namespace. Let's have a look at what these are and how they can help us to test various constructs. We will shortly introduce the most commonly used concepts so that you are familiar with them as we present them more deeply further on: The TestBed class is the most important concept and creates its own testing module. In reality, when you test out a construct to detach it from the module it resides in and reattach it to the testing module created by the TestBed. The TestBed class has a configureTestModule() helper method that we use to set up the test module as needed. The TestBed can also instantiate components. ComponentFixture is a class wrapping the component instance. This means that it has some functionality on it and it has a member that is the component instance itself. The DebugElement, much like the ComponentFixture, acts as a wrapper. It, however, wraps the DOM element and not the component instance. It's a bit more than that though, as it has an injector on it that allows us to access the services that have been injected into a component. This was a brief overview of our testing environment, the frameworks, and libraries used. Now let's discuss component testing. Introduction to component testing A usual method of operation for doing anything Angular is to use the Angular CLI. Working with tests is no different. The Angular CLI lets us create tests, debug them, and run them; it also gives us an understanding of how well our tests cover the code and its many scenarios. Component testing with dependencies We have learned a lot already, but let's face it, no component that we build will be as simple as the one we wrote in the preceding section. There will almost certainly be at least one dependency, looking like this: @Component({}) export class ExampleComponent { constructor(dependency:Dependency) {} } We have different ways of dealing with testing such a situation. One thing is clear though: if we are testing the component, then we should not test the service as well. This means that when we set up such a test, the dependency should not be the real thing. There are different ways of dealing with that when it comes to unit testing; no solution is strictly better than the other: Using a stub means that we tell the dependency injector to inject a stub that we provide, instead of the real thing. Injecting the real thing, but attaching a spy, to the method that we call in our component. Regardless of the approach, we ensure that the test is not performing a side effect such as talking to a filesystem or attempting to communicate via HTTP; we are, using this approach, isolated. Using a stub to replace the dependency Using a stub means that we completely replace what was there before. It is as simple to do as instructing the TestBed in the following way: TestBed.configureTestingModule({ declarations: [ExampleComponent] providers: [{ provide: DependencyService, useClass: DependencyServiceStub }] }); We define a providers array like we do with the NgModule, and we give it a list item that points out the definition we intend to replace and we give it the replacement instead; that is our stub. Let's now build our DependencyStub to look like this: class DependencyServiceStub { getData() { return 'stub'; } } Just like with an @NgModule, we are able to override the definition of our dependency with our own stub. Imagine our component looks like the following: import { Component } from '@angular/core'; import { DependencyService } from "./dependency.service"; @Component({ selector: 'example', template: ` <div>{{ title }}</div> ` }) export class ExampleComponent { title: string; constructor(private dependency: DependencyService) { this.title = this.dependency.getData(); } } Here we pass an instance of the dependency in the constructor. With our testing module correctly set up, with our stub, we can now write a test that looks like this: it(`should have as title 'stub'`, async(() => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; expect(app.title).toEqual('stub'); })); The test looks normal, but at the point when the dependency would be called in the component code, our stub takes its place and responds instead. Our dependency should be overridden, and as you can see, the expect(app.title).toEqual('stub') assumes the stub will answer, which it does. Spying on the dependency method The previously-mentioned approach, using a stub, is not the only way to isolate ourselves in a unit test. We don't have to replace the entire dependency, only the parts that our component is using. Replacing certain parts means that we point out specific methods on the dependency and assign a spy to them. A spy is an interesting construct; it has the ability to answer what you want it to answer, but you can also see how many times it is being called and with what argument/s, so a spy gives you a lot more information about what is going on. Let's have a look at how we would set a spy up: beforeEach(() => { TestBed.configureTestingModule({ declarations: [ExampleComponent], providers: [DependencyService] }); dependency = TestBed.get(DependencyService); spy = spyOn( dependency,'getData'); fixture = TestBed.createComponent(ExampleComponent); }) Now as you can see, the actual dependency is injected into the component. After that, we grab a reference to the component, our fixture variable. This is followed by us using the TestBed.get('Dependency') to get hold of the dependency inside of the component. At this point, we attach a spy to its getData() method through the spyOn( dependency,'getData') call. This is not enough, however; we have yet to instruct the spy what to respond with when being called. Let us do just that: spyOn(dependency,'getData').and.returnValue('spy value'); We can now write our test as usual: it('test our spy dependency', () => { var component = fixture.debugElement.componentInstance; expect(component.title).toBe('spy value'); }); This works as expected, and our spy responds as it should. Remember how we said that spies were capable of more than just responding with a value, that you could also check whether they were invoked and with what? To showcase this, we need to improve our tests a little bit and check for this extended functionality, like so: it('test our spy dependency', () => { var component = fixture.debugElement.componentInstance; expect(spy.calls.any()).toBeTruthy(); }) You can also check for the number of times it was called, with spy.callCount, or whether it was called with some specific arguments: spy.mostRecentCalls.args or spy.toHaveBeenCalledWith('arg1', 'arg2'). Remember if you use a spy, make sure it pays for itself by you needing to do checks like these; otherwise, you might as well use a stub. Spies are a feature of the Jasmine framework, not Angular. The interested reader is urged to research this topic further at http://tobyho.com/2011/12/15/jasmine-spy-cheatsheet/. Async services Very few services are nice and well-behaved, in the sense that they are synchronous. A lot of the time, your service will be asynchronous and the return from it is most likely an observable or a promise. If you are using RxJS with the Http service or HttpClient, it will be observable, but if using the fetch API, it will be a promise. These are two good options for dealing with HTTP, but the Angular team added the RxJS library to Angular to make your life as a developer easier. Ultimately it's up to you, but we recommend going with RxJS. Angular has two constructs ready to tackle the asynchronous scenario when testing: async() and whenStable(): This code ensures that any promises are immediately resolved; it can look more synchronous though fakeAsync() and tick(): This code does what the async does but it looks more synchronous when used Let's describe the async() and whenStable() approaches. Our service has now grown up and is doing something asynchronous when we call it like a timeout or an HTTP call. Regardless of which, the answer doesn't reach us straightaway. By using async() in combination with whenStable(), we can, however, ensure that any promises are immediately resolved. Imagine our service now looks like this: export class AsyncDependencyService { getData(): Promise<string> { return new Promise((resolve, reject) => { setTimeout(() => { resolve('data') }, 3000); }) } } We need to change our spy setup to return a promise instead of returning a static string, like so: spy = spyOn(dependency,'getData') .and.returnValue(Promise.resolve('spy data')); We do need to change inside of our component, like so: import { Component, OnInit } from '@angular/core'; import { AsyncDependencyService } from "./async.dependency.service"; @Component({ selector: 'async-example', template: ` <div>{{ title }}</div> ` }) export class AsyncExampleComponent { title: string; constructor(private service: AsyncDependencyService) { this.service.getData().then(data => this.title = data); } } At this point, it's time to update our tests. We need to do two more things. We need to tell our test method to use the async() function, like so: it('async test', async() => { // the test body }) We also need to call fixture.whenStable() to make sure that the promise will have had ample time to resolve, like so: import { TestBed } from "@angular/core/testing"; import { AsyncExampleComponent } from "./async.example.component"; import { AsyncDependencyService } from "./async.dependency.service"; describe('test an component with an async service', () => { let fixture; beforeEach(() => { TestBed.configureTestingModule({ declarations: [AsyncExampleComponent], providers: [AsyncDependencyService] }); fixture = TestBed.createComponent(AsyncExampleComponent); }); it('should contain async data', async () => { const component = fixture.componentInstance; fixture.whenStable.then(() => { fixture.detectChanges(); expect(component.title).toBe('async data'); }); }); }); This version of doing it works as it should, but feels a bit clunky. There is another approach using fakeAsync() and tick(). Essentially, fakeAsync() replaces the async() call and we get rid of whenStable(). The big benefit, however, is that we no longer need to place our assertion statements inside of the promise's then() callback. This gives us synchronous-looking code. Back to fakeAsync(), we need to make a call to tick(), which can only be called within a fakeAsync() call, like so: it('async test', fakeAsync() => { let component = fixture.componentInstance; fixture.detectChanges(); fixture.tick(); expect(component.title).toBe('spy data'); }); As you can see, this looks a lot cleaner; which version you want to use for async testing is up to you. Testing pipes A pipe is basically a class that implements the PipeTransform interface, thus exposing a transform() method that is usually synchronous. Pipes are therefore very easy to test. We will begin by testing a simple pipe, creating, as we mentioned, a test spec right next to its code unit file. The code is as follows: import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'formattedpipe' }) export class FormattedPipe implements PipeTransform { transform(value: any, ...args: any[]): any { return "banana" + value; } } Our code is very simple; we take a value and add banana to it. Writing a test for it is equally simple. The only thing we need to do is to import the pipe and verify two things: That it has a transform method That it produces the expected results The following code writes a test for each of the bullet points listed earlier: import FormattedTimePipe from './formatted-time.pipe'; import { TestBed } from '@angular/core/testing'; describe('A formatted time pipe' , () => { let fixture; beforeEach(() => { fixture = new FormattedTimePipe(); }) // Specs with assertions it('should expose a transform() method', () => { expect(typeof formattedTimePipe.transform).toEqual('function'); }); it('should produce expected result', () => { expect(fixture.transform( 'val' )).toBe('bananaval'); }) }); In our beforeEach() method, we set up the fixture by instantiating the pipe class. In the first test, we ensure that the transform() method exists. This is followed by our second test that asserts that the transform() method produces the expected result. We saw how to code powerful tests for our components and pipes. If you found this post useful, be sure to check out the book Learning Angular (Second Edition) to learn about mocking HTTP responses and unit testing for routes, input, and output, directives, etc. Getting started with Angular CLI and build your first Angular Component Building Components Using Angular Why switch to Angular for web development – Interview with Minko Gechev
Read more
  • 0
  • 0
  • 17745

article-image-build-botnet-detectors-using-machine-learning-algorithms-in-python-tutorial
Melisha Dsouza
26 Aug 2018
12 min read
Save for later

Build botnet detectors using machine learning algorithms in Python [Tutorial]

Melisha Dsouza
26 Aug 2018
12 min read
Botnets are connected computers that perform a number of repetitive tasks to keep websites going. Connected devices play an important role in modern life. From smart home appliances, computers, coffee machines, and cameras, to connected cars, this huge shift in our lifestyles has made our lives easier. Unfortunately, these exposed devices could be easily targeted by attackers and cybercriminals who could use them later to enable larger-scale attacks. Security vendors provide many solutions and products to defend against botnets, but in this tutorial, we are going to learn how to build novel botnet detection systems with Python and machine learning techniques. You will find all the code discussed, in addition to some other useful scripts, in the following repository: https://github.com/PacktPublishing/Mastering-Machine-Learning-for-Penetration-Testing/tree/master/Chapter05 This article is an excerpt from a book written by Chiheb Chebbi titled Mastering Machine Learning for Penetration Testing We are going to learn how to build different botnet detection systems with many machine learning algorithms. As a start to a first practical lab, let's start by building a machine learning-based botnet detector using different classifiers. By now, I hope you have acquired a clear understanding about the major steps of building machine learning systems. So, I believe that you already know that, as a first step, we need to look for a dataset. Many educational institutions and organizations are given a set of collected datasets from internal laboratories. One of the most well known botnet datasets is called the CTU-13 dataset. It is a labeled dataset with botnet, normal, and background traffic delivered by CTU University, Czech Republic. During their work, they tried to capture real botnet traffic mixed with normal traffic and background traffic. To download the dataset and check out more information about it, you can visit the following link: https://mcfp.weebly.com/the-ctu-13-dataset-a-labeled-dataset-with-botnet-normal-and-background-traffic.html. The dataset is bidirectional NetFlow files. But what are bidirectional NetFlow files? Netflow is an internet protocol developed by Cisco. The goal of this protocol is to collect IP traffic information and monitor network traffic in order to have a clearer view about the network traffic flow. The main components of a NetFlow architecture are a NetFlow Exporter, a Netflow collector, and a Flow Storage. The following diagram illustrates the different components of a NetFlow infrastructure: When it comes to NetFlow generally, when host A sends an information to host B and from host B to host A as a reply, the operation is named unidirectional NetFlow. The sending and the reply are considered different operations. In bidirectional NetFlow, we consider the flows from host A and host B as one flow. Let's download the dataset by using the following command: $ wget --no-check-certificate https://mcfp.felk.cvut.cz/publicDatasets/CTU-13-Dataset/CTU-13-Dataset.tar.bz2 Extract the downloaded tar.bz2 file by using the following command: # tar xvjf CTU-13-Dataset.tar.bz2 The file contains all the datasets, with the different scenarios. For the demonstration, we are going to use dataset 8 (scenario 8). You can select any scenario or you can use your own collected data, or any other .binetflow files delivered by other institutions: Load the data using pandas as usual: >>> import pandas as pd >>> data = pd.read_csv("capture20110816-3.binetflow") >>> data['Label'] = data.Label.str.contains("Botnet") Exploring the data is essential in any data-centric project. For example, you can start by checking the names of the features or the columns: >> data.columns The command results in the columns of the dataset: StartTime, Dur, Proto, SrcAddr, Sport, Dir, DstAddr, Dport, State, sTos, dTos, TotPkts, TotBytes, SrcBytes, and Label. The columns represent the features used in the dataset; for example, Dur represents duration, Sport represents the source port, and so on. You can find the full list of features in the chapter's GitHub repository. Before training the model, we need to build some scripts to prepare the data. This time, we are going to build a separate Python script to prepare data, and later we can just import it into the main script. I will call the first script DataPreparation.py. There are many proposals done to help extract the features and prepare data to build botnet detectors using machine learning. In our case, I customized two new scripts inspired by the data loading scripts built by NagabhushanS: from __future__ import division import os, sys import threading After importing the required Python packages, we created a class called Prepare to select training and testing data: class Prepare(threading.Thread): def __init__(self, X, Y, XT, YT, accLabel=None): threading.Thread.__init__(self) self.X = X self.Y = Y self.XT=XT self.YT=YT self.accLabel= accLabel def run(self): X = np.zeros(self.X.shape) Y = np.zeros(self.Y.shape) XT = np.zeros(self.XT.shape) YT = np.zeros(self.YT.shape) np.copyto(X, self.X) np.copyto(Y, self.Y) np.copyto(XT, self.XT) np.copyto(YT, self.YT) for i in range(9): X[:, i] = (X[:, i] - X[:, i].mean()) / (X[:, i].std()) for i in range(9): XT[:, i] = (XT[:, i] - XT[:, i].mean()) / (XT[:, i].std()) The second script is called LoadData.py. You can find it on GitHub and use it directly in your projects to load data from .binetflow files and generate a pickle file. Let's use what we developed previously to train the models. After building the data loader and preparing the machine learning algorithms that we are going to use, it is time to train and test the models. First, load the data from the pickle file, which is why we need to import the pickle Python library. Don't forget to import the previous scripts using: import LoadData import DataPreparation import pickle file = open('flowdata.pickle', 'rb') data = pickle.load(file) Select the data sections: Xdata = data[0] Ydata = data[1] XdataT = data[2] YdataT = data[3] As machine learning classifiers, we are going to try many different algorithms so later we can select the best algorithm for our model. Import the required modules to use four machine learning algorithms from sklearn: from sklearn.linear_model import * from sklearn.tree import * from sklearn.naive_bayes import * from sklearn.neighbors import * Prepare the data by using the previous module build. Don't forget to import DataPreparation by typing import DataPreparation: >>> DataPreparation.Prepare(Xdata,Ydata,XdataT,YdataT) Now, we can train the models; and to do that, we are going to train the model with different techniques so later we can select the most suitable machine learning technique for our project. The steps are like what we learned in previous projects: after preparing the data and selecting the features, define the machine learning algorithm, fit the model, and print out the score after defining its variable. As machine learning classifiers, we are going to test many of them. Let's start with a decision tree: Decision tree model: >>> clf = DecisionTreeClassifier() >>> clf.fit(Xdata,Ydata) >>> Prediction = clf.predict(XdataT) >>> Score = clf.score(XdataT,YdataT) >>> print (“The Score of the Decision Tree Classifier is”, Score * 100) The score of the decision tree classifier is 99% Logistic regression model: >>> clf = LogisticRegression(C=10000) >>> clf.fit(Xdata,Ydata) >>> Prediction = clf.predict(XdataT) >>> Score = clf.score(XdataT,YdataT) >>> print ("The Score of the Logistic Regression Classifier is", Score * 100) The score of the logistic regression classifier is 96% Gaussian Naive Bayes model: >>> clf = GaussianNB() >>> clf.fit(Xdata,Ydata) >>> Prediction = clf.predict(XdataT) >>> Score = clf.score(XdataT,YdataT) >>> print("The Score of the Gaussian Naive Bayes classifier is", Score * 100) The score of the Gaussian Naive Bayes classifier is 72% k-Nearest Neighbors model: >>> clf = KNeighborsClassifier() >>> clf.fit(Xdata,Ydata) >>> Prediction = clf.predict(XdataT) >>> Score = clf.score(XdataT,YdataT) >>> print("The Score of the K-Nearest Neighbours classifier is", Score * 100) The score of the k-Nearest Neighbors classifier is 96% Neural network model: To build a Neural network Model use the following code: >>> from keras.models import * >>> from keras.layers import Dense, Activation >>> from keras.optimizers import * model = Sequential() model.add(Dense(10, input_dim=9, activation="sigmoid")) model.add(Dense(10, activation='sigmoid')) model.add(Dense(1)) sgd = SGD(lr=0.01, decay=0.000001, momentum=0.9, nesterov=True) model.compile(optimizer=sgd, loss='mse') model.fit(Xdata, Ydata, nb_epoch=200, batch_size=100) Score = model.evaluate(XdataT, YdataT, verbose=0) Print(“The Score of the Neural Network is”, Score * 100 ) With this code, we imported the required Keras modules, we built the layers, we compiled the model with an SGD optimizer, we fit the model, and we printed out the score of the model. How to build a Twitter bot detector In the previous sections, we saw how to build a machine learning-based botnet detector. In this new project, we are going to deal with a different problem instead of defending against botnet malware. We are going to detect Twitter bots because they are also dangerous and can perform malicious actions. For the model, we are going to use the NYU Tandon Spring 2017 Machine Learning Competition: Twitter Bot classification dataset. You can download it from this link: https://www.kaggle.com/c/twitter-bot-classification/data. Import the required Python packages: >>> import pandas as pd >>> import numpy as np >>> import seaborn Let's load the data using pandas and highlight the bot and non-bot data: >>> data = pd.read_csv('training_data_2_csv_UTF.csv') >>> Bots = data[data.bot==1] >> NonBots = data[data.bot==0] Visualization with seaborn In every project, I want to help you discover new data visualization Python libraries because, as you saw, data engineering and visualization are essential to every modern data-centric project. This time, I chose seaborn to visualize the data and explore it before starting the training phase. Seaborn is a Python library for making statistical visualizations. The following is an example of generating a plot with seaborn: >>> data = np.random.multivariate_normal([0, 0], [[5, 2], [2, 2]], size=2000) >>> data = pd.DataFrame(data, columns=['x', 'y']) >>> for col in 'xy': ... seaborn.kdeplot(data[col], shade=True) For example, in our case, if we want to identify the missing data: matplotlib.pyplot.figure(figsize=(10,6)) seaborn.heatmap(data.isnull(), yticklabels=False, cbar=False, cmap='viridis') matplotlib.pyplot.tight_layout() The previous two code snippets were some examples to learn how to visualize data. Visualization helps data scientists to explore and learn more about the data. Now, let's go back and continue building our model. Identify the bag of words by selecting some bad words used by Twitter bots. The following is an example of bad words used by a bot. Of course, you can add more words: bag_of_words_bot = r'bot|b0t|cannabis|tweet me|mishear|follow me|updates every|gorilla|yes_ofc|forget' \ r'expos|kill|bbb|truthe|fake|anony|free|virus|funky|RNA|jargon' \ r'nerd|swag|jack|chick|prison|paper|pokem|xx|freak|ffd|dunia|clone|genie|bbb' \ r'ffd|onlyman|emoji|joke|troll|droop|free|every|wow|cheese|yeah|bio|magic|wizard|face' Now, it is time to identify training features: data['screen_name_binary'] = data.screen_name.str.contains(bag_of_words_bot, case=False, na=False) data['name_binary'] = data.name.str.contains(bag_of_words_bot, case=False, na=False) data['description_binary'] = data.description.str.contains(bag_of_words_bot, case=False, na=False) data['status_binary'] = data.status.str.contains(bag_of_words_bot, case=False, na=False) Feature extraction: Let's select features to use in our model: data['listed_count_binary'] = (data.listed_count>20000)==False features = ['screen_name_binary', 'name_binary', 'description_binary', 'status_binary', 'verified', 'followers_count', 'friends_count', 'statuses_count', 'listed_count_binary', 'bot'] Now, train the model with a decision tree classifier: from sklearn.tree import DecisionTreeClassifier from sklearn.metrics import accuracy_score, roc_curve, auc from sklearn.model_selection import train_test_split We import some previously discussed modules: X = data[features].iloc[:,:-1] y = data[features].iloc[:,-1] We define the classifier: clf = DecisionTreeClassifier(criterion='entropy', min_samples_leaf=50, min_samples_split=10) We split the classifier: X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=101) We fit the model: clf.fit(X_train, y_train) y_pred_train = clf.predict(X_train) y_pred_test = clf.predict(X_test) We print out the accuracy scores: print("Training Accuracy: %.5f" %accuracy_score(y_train, y_pred_train)) print("Test Accuracy: %.5f" %accuracy_score(y_test, y_pred_test)) Our model detects Twitter bots with an 88% detection rate, which is a good accuracy rate. This technique is not the only possible way to detect botnets. Researchers have proposed many other models based on different machine learning algorithms, such as Linear SVM and decision trees. All these techniques have an accuracy of 90%. Most studies showed that feature engineering was a key contributor to improving machine learning models. To study a real-world case, check out a paper called What we learn from learning - Understanding capabilities and limitations of machine learning in botnet attacks (https://arxiv.org/pdf/1805.01333.pdf), conducted by David Santana, Shan Suthaharan, and Somya Mohanty. Summary In this tutorial, we learned how to build a botnet detector and a Twitter botnet detecter with different machine learning algorithms. To become a master at penetration testing using machine learning with Python, check out this book Mastering Machine Learning for Penetration Testing Cisco and Huawei Routers hacked via backdoor attacks and botnets How to protect yourself from a botnet attack Tackle trolls with Machine Learning bots: Filtering out inappropriate content just got easy
Read more
  • 0
  • 0
  • 17012

article-image-understanding-amazon-machine-learning-workflow
Natasha Mathur
24 Aug 2018
11 min read
Save for later

Understanding Amazon Machine Learning Workflow [ Tutorial ]

Natasha Mathur
24 Aug 2018
11 min read
This article presents an overview of the workflow of a simple Amazon Machine Learning (Amazon ML) project. Amazon Machine Learning is an online service by Amazon Web Services (AWS) that does supervised learning for predictive analytics. Launched in April 2015 at the AWS Summit, Amazon ML joins a growing list of cloud-based machine learning services, such as Microsoft Azure, Google prediction, IBM Watson, Prediction IO, BigML, and many others. These online machine learning services form an offer commonly referred to as Machine Learning as a Service or MLaaS following a similar denomination pattern of other cloud-based services such as SaaS, PaaS, and IaaS respectively for Software, Platform, or Infrastructure as a Service. The Amazon ML workflow closely follows a standard Data Science workflow with steps: Extract the data and clean it up. Make it available to the algorithm. Split the data into a training and validation set, typically a 70/30 split with equal distribution of the predictors in each part. Select the best model by training several models on the training dataset and comparing their performances on the validation dataset. Use the best model for predictions on new data. This article is an excerpt taken from the book 'Effective Amazon Machine Learning' written by Alexis Perrier. As shown in the following Amazon ML menu, the service is built around four objects: Datasource ML model Evaluation Prediction The Datasource and Model can also be configured and set up in the same flow by creating a new Datasource and ML model. We will take a closer look at the Datasource and ML model. Amazon ML  dataset For the rest of the article, we will use the simple Predicting Weight by Height and Age dataset (from Lewis Taylor (1967)) with 237 samples of children's age, weight, height, and gender, which is available at https://v8doc.sas.com/sashtml/stat/chap55/sect51.htm. This dataset is composed of 237 rows. Each row has the following predictors: sex (F, M), age (in months), height (in inches), and we are trying to predict the weight (in lbs) of these children. There are no missing values and no outliers. The variables are close enough in range and normalization is not required. In short, we do not need to carry out any preprocessing or cleaning on the original dataset. Age, height, and weight are numerical variables (real-valued), and sex is a categorical variable. We will randomly select 20% of the rows as the held-out subset to use for the prediction of previously unseen data and keep the other 80% as training and evaluation data. This data split can be done in Excel or any other spreadsheet editor: By creating a new column with randomly generated numbers Sorting the spreadsheet by that column Selecting 190 rows for training and 47 rows for prediction (roughly a 80/20 split) Let us name the training set LT67_training.csv and the held-out set that we will use for prediction LT67_heldout.csv, where LT67 stands for Lewis and Taylor, the creator of this dataset in 1967. Note that it is important for the distribution in age, sex, height, and weight to be similar in both subsets. We want the data on which we will make predictions to show patterns that are similar to the data on which we will train and optimize our model. Loading the data on Amazon S3 Follow these steps to load the training and held-out datasets on S3: Go to your s3 console at https://console.aws.amazon.com/s3. Create a bucket if you haven't done so already. Buckets are basically folders that are uniquely named across all S3. We created a bucket named aml.packt. Since that name has now been taken, you will have to choose another bucket name if you are following along with this demonstration. Click on the bucket name you created and upload both the LT67_training.csv and LT67_heldout.csv files by selecting Upload from the Actions drop-down menu: Both files are small, only a few KB, and hosting costs should remain negligible for that exercise. Note that for each file, by selecting the Properties tab on the right, you can specify how your files are accessed, what user, role, group or AWS service may download, read, write, and delete the files, and whether or not they should be accessible from the Open Web. When creating the datasource in Amazon ML, you will be prompted to grant Amazon ML access to your input data. You can specify the access rules to these files now in S3 or simply grant access later on. Our data is now in the cloud in an S3 bucket. We need to tell Amazon ML where to find that input data by creating a datasource. We will first create the datasource for the training file ST67_training.csv. Declaring a datasource Go to the Amazon ML dashboard, and click on Create new... | Datasource and ML model. We will use the faster flow available by default: As shown in the following screenshot, you are asked to specify the path to the LT67_training.csv file {S3://bucket}{path}{file}. Note that the S3 location field automatically populates with the bucket names and file names that are available to your user: Specifying a Datasource name is used to organize your Amazon ML assets. By clicking on Verify, Amazon ML will make sure that it has the proper rights to access the file. In case it needs to be granted access to the file, you will be prompted to do so as shown in the following screenshot: Just click on Yes to grant access. At this point, Amazon ML will validate the datasource and analyze its contents. Creating the datasource An Amazon ML datasource is composed of the following: The location of the data file: The data file is not duplicated or cloned in Amazon ML but accessed from S3 The schema that contains information on the type of the variables contained in the CSV file: Categorical Text Numeric (real-valued) Binary It is possible to supply Amazon ML with your own schema or modify the one created by Amazon ML. At this point, Amazon ML has a pretty good idea of the type of data in your training dataset. It has identified the different types of variables and knows how many rows it has: Move on to the next step by clicking on Continue, and see what schema Amazon ML has inferred from the dataset as shown in the next screenshot: Amazon ML needs to know at that point which is the variable you are trying to predict. Be sure to tell Amazon ML the following: The first line in the CSV file contains te column name The target is the weight We see here that Amazon ML has correctly inferred the following: sex is categorical age, height, and weight are numeric (continuous real values) Since we chose a numeric variable as the target Amazon ML, will use Linear Regression as the predictive model. For binary or categorical values, we would have used Logistic Regression. This means that Amazon ML will try to find the best a, b, and c coefficients so that the weight predicted by the following equation is as close as possible to the observed real weight present in the data: predicted weight = a * age + b * height + c * sex Amazon ML will then ask you if your data contains a row identifier. In our present case, it does not. Row identifiers are used when you want to understand the prediction obtained for each row or add an extra column to your dataset later on in your project. Row identifiers are for reference purposes only and are not used by the service to build the model. You will be asked to review the datasource. You can go back to each one of the previous steps and edit the parameters for the schema, the target, and the input data. Now that the data is known to Amazon ML, the next step is to set up the parameters of the algorithm that will train the model. The machine learning model We select the default parameters for the training and evaluation settings. Amazon ML will do the following: Create a step for data transformation based on the statistical properties it has inferred from the dataset Split the dataset (ST67_training.csv) into a training part and a validation part, with a 70/30 split. The split strategy assumes the data has already been shuffled and can be split sequentially. The step will be used to transform the data in a similar way for the training and the validation datasets. The only transformation suggested by Amazon ML is to transform the categorical variable sex into a binary variable, where m = 0 and f = 1 for instance. No other transformation is needed. The default advanced settings for the model are shown in the following screenshot: We see that Amazon ML will pass over the data 10 times, shuffle splitting the data each time. It will use an L2 regularization strategy based on the sum of the square of the coefficients of the regression to prevent overfitting. We will evaluate the predictive power of the model using our LT67_heldout.csv dataset later on. Regularization comes in 3 levels with a mild (10^-6), medium (10^-4), or aggressive (10^-02) setting, each value stronger than the previous one. The default setting is mild, the lowest, with a regularization constant of 0.00001 (10^-6) implying that Amazon ML does not anticipate much overfitting on this dataset. This makes sense when the number of predictors, three in our case, is much smaller than the number of samples (190 for the training set). Clicking on the Create ML model button will launch the model creation. This takes a few minutes to resolve, depending on the size and complexity of your dataset. You can check its status by refreshing the model page. In the meantime, the model status remains pending. At that point, Amazon ML will split our training dataset into two subsets: a training and a validation set. It will use the training portion of the data to train several settings of the algorithm and select the best one based on its performance on the training data. It will then apply the associated model to the validation set and return an evaluation score for that model. By default, Amazon ML will sequentially take the first 70% of the samples for training and the remaining 30% for validation. It's worth noting that Amazon ML will not create two extra files and store them on S3, but instead create two new datasources out of the initial datasource we have previously defined. Each new datasource is obtained from the original one via a Data rearrangement JSON recipe such as the following: { "splitting": { "percentBegin": 0, "percentEnd": 70 } } You can see these two new datasources in the Datasource dashboard. Three datasources are now available where there was initially only one, as shown by the following screenshot: While the model is being trained, Amazon ML runs the Stochastic Gradient algorithm several times on the training data with different parameters: Varying the learning rate in increments of powers of 10: 0.01, 0.1, 1, 10, and 100. Making several passes over the training data while shuffling the samples before each path. At each pass, calculating the prediction error, the Root Mean Squared Error (RMSE), to estimate how much of an improvement over the last pass was obtained. If the decrease in RMSE is not really significant, the algorithm is considered to have converged, and no further pass shall be made. At the end of the passes, the setting that ends up with the lowest RMSE wins, and the associated model (the weights of the regression) is selected as the best version. Once the model has finished training, Amazon ML evaluates its performance on the validation datasource. Once the evaluation itself is also ready, you have access to the model's evaluation. The Amazon ML flow is smooth and facilitates the inherent data science loop: data, model, evaluation, and prediction. We looked at an overview of the workflow of a simple Amazon Machine Learning (Amazon ML) project. We discussed two objects of the Amazon ML menu: Datasource and ML model. If you found this post useful, be sure to check out the book 'Effective Amazon Machine Learning' to learn about evaluation and prediction in Amazon ML along with other AWS ML concepts. Integrate applications with AWS services: Amazon DynamoDB & Amazon Kinesis [Tutorial] AWS makes Amazon Rekognition, its image recognition AI, available for Asia-Pacific developers
Read more
  • 0
  • 0
  • 2250

article-image-setting-up-jasmine-for-unit-testing-in-angular
Natasha Mathur
24 Aug 2018
8 min read
Save for later

Setting up Jasmine for Unit Testing in Angular [Tutorial]

Natasha Mathur
24 Aug 2018
8 min read
Web developers work hard to build a working application that they can be proud of. But how can we ensure a painless maintainability in the future? A comprehensive automated testing layer will become our lifeline once our application begins to scale up and we have to mitigate the impact of bugs caused by new functionalities colliding with the already existing ones. In this article, we will see why we need to perform unit testing and the process of setting up Jasmine for our tests. This tutorial is an excerpt taken from the book 'Learning Angular - second edition' written by Christoffer Noring, Pablo Deeleman.  Why do we need unit tests? What is a unit test? Unit tests are part of an engineering philosophy that takes a stand for efficient and agile development processes, by adding an additional layer of automated testing to the code, before it is developed. The core concept is that each piece of code is delivered with its own test, and both pieces of code are built by the developer who is working on that code. First, we design the test against the module we want to deliver, checking the accuracy of its output and behavior. Since the module is still not implemented, the test will fail. Hence, our job is to build the module in such a way that it passes its own test. Unit testing is quite controversial. While there is a common agreement about how beneficial test-driven development for ensuring code quality and maintenance over time is, not everybody undertakes unit testing in their daily practice. Why is that? Well, building tests while we develop our code can feel like a burden sometimes, particularly when the test winds up being bigger in size than the piece of functionality it aims to test. However, the arguments favoring testing outnumber the arguments against it: Building tests contribute to better code design. Our code must conform to the test requirements and not the other way around. In that sense, if we try to test an existing piece of code and we find ourselves blocked at some point, chances are that the piece of code we aim to test is not well designed and shows off a convoluted interface that requires some rethinking. On the other hand, building testable modules can help with early detection of side effects on other modules. Refactoring tested code is the lifeline against introducing bugs in later stages. Any development is meant to evolve with time, and on every refactor the risk of introducing a bug, that will only pop up in another part of our application, is high. Unit tests are a good way to ensure that we catch bugs at an early stage, either when introducing new features or when updating existing ones. Building tests is a good way to document our code APIs and functionalities. And this becomes a priceless resource when someone not acquainted with the code base takes over the development endeavor. These are only a few arguments, but you can find countless resources on the web about the benefits of testing your code. If you do not feel convinced yet, give it a try. Otherwise, let's continue with our journey and see the overall form of a test. Unit testing in Jasmine There are many different ways to test a piece of code, but in this article, we will look at the anatomy of a test, what it is made up of. The first thing we need, for testing any code, is a test framework. The test framework should provide utility functions for building test suites, containing one or several test specs each. So what are these concepts? Test suite: A suite creates a logical grouping for a bunch of tests. A suite can, for example, be all the tests for a product page. Test spec: This is another name for a unit test. The following shows what a test file can look like where we are using a test suite and placing a number of related tests inside. The chosen framework for this is Jasmine. In Jasmine, the describe() function helps us to define a test suite. The describe() method takes a name as the first parameter and a function as the second parameter. Inside of the describe() function are a number of invocations to the it() method. The it() function is our unit test; it takes the name of the test as the first parameter and a function as the second parameter: // Test suite describe('A math library', () => { // Test spec it('add(1,1,) should return 2', () => { // Test spec implementation goes here }); }); Each test spec checks out a specific functionality of the feature described in the suite description argument and declares one or several expectations in its body. Each expectation takes a value, which we call the expected value, and is compared against an actual value by means of a matcher function, which checks whether expected and actual values match accordingly. This is what we call an assertion, and the test framework will pass or fail the spec depending on the result of such assertions. The code is as follows: // Test suite describe('A math library', () => { // Test spec it('add(1,1) should return 2', () => { // Test assertion expect(add(1,1,)).toBe(2); }); it('subtract(2,1)', () =>{ //Test assertion expect(subtract(2,1)).toBe(1); }) }); In the previous example, add(1,1) will return the actual value that is supposed to match the expected value declared in the toBe() matcher function. Worth noting from the previous example is the addition of a second test that tests our subtract() function. We can clearly see that this test deals with yet another mathematical operation, thus it makes sense to group both these tests under one suite. So far, we have learned about test suites and how to group tests according to their function. Furthermore, we have learned about invoking the code you want to test and asserting that it does what you think it does. There are, however, more concepts to a unit test worth knowing about, namely setup and teardown functionality. A setup functionality is something that sets up your code before the test is run usually. It's a way to keep your code cleaner so you can focus on just invoking the code and asserting. A tear-down functionality is the opposite of a setup functionality and is dedicated to tearing down what you set up initially; essentially it's a way to clean up after the test. Let's see how this can look in practice with a code example, using the Jasmine framework. In Jasmine, the beforeEach() method is used for setup functionality; it runs before every unit test. The afterEach() method is used to run tear-down logic. The code is as follows: describe('a Product service', () => { let productService; beforeEach(() => { productService = new ProductService(); }); it('should return data', () => { let actual = productService.getData(); assert(actual.length).toBe(1); }); afterEach(() => { productService = null; }); }); We can see in the preceding code how the beforeEach() function is responsible for instantiating the productService, which means the test only has to care about invoking production code and asserting the outcome. This makes the test look cleaner. It should be said, though, in reality, tests tend to have a lot of setup going on and having a beforeEach() function can really make the tests look cleaner; above all, it tends to make it easier to add new tests, which is great. What you want at the end of the day is well-tested code; the easier it is to write and maintain such code, the better for your software. Testing web applications in general and Angular applications, in particular, poses a myriad of scenarios that usually need a specific approach. Remember that if a specific test requires a cumbersome and convoluted solution, we are probably facing a good case for a module redesign instead. There are several paths to compound our knowledge of web application testing in Angular and enable us to become great testing ninjas.  In this we saw the importance of unit testing in our Angular applications, the basic shape of a unit test, and the process of setting up Jasmine for our tests. If you found this post useful, do check out the book 'Learning Angular - Second Edition'  to learn more about unit testing and how to implement it for routes, inputs, outputs, directives, etc. Everything new in Angular 6: Angular Elements, CLI commands and more Angular 6 is here packed with exciting new features! Getting started with Angular CLI and build your first Angular Component
Read more
  • 0
  • 0
  • 3092

article-image-decorators-as-higher-order-functions-python
Aaron Lazar
24 Aug 2018
7 min read
Save for later

Using Decorators as higher-order functions in Python [Tutorial]

Aaron Lazar
24 Aug 2018
7 min read
The core idea of a decorator is to transform some original function into another form. A decorator creates a kind of composite function based on the decorator and the original function being decorated. In this tutorial, we'll understand how decorators can be used as higher-order functions in Python. This article is an extract from the 2nd edition of the bestseller, Functional Python Programming, authored by Steven Lott.  Working with Decorator function A decorator function can be used in one of the two following ways: As a prefix that creates a new function with the same name as the base function as follows: @decorator def original_function(): pass As an explicit operation that returns a new function, possibly with a new name: def original_function(): pass original_function = decorator(original_function) These are two different syntaxes for the same operation. The prefix notation has the advantages of being tidy and succinct. The prefix location is more visible to some readers. The suffix notation is explicit and slightly more flexible. While the prefix notation is common, there is one reason for using the suffix notation: we may not want the resulting function to replace the original function. We mayt want to execute the following command that allows us to use both the decorated and the undecorated functions: new_function = decorator(original_function) This will build a new function, named new_function(), from the original function. Python functions are first-class objects. When using the @decorator syntax, the original function is no longer available for use. A decorator is a function that accepts a function as an argument and returns a function as the result. This basic description is clearly a built-in feature of the language. The open question then is how do we update or adjust the internal code structure of a function? The answer is we don't. Rather than messing about with the inside of the code, it's much cleaner to define a new function that wraps the original function. It's easier to process the argument values or the result and leave the original function's core processing alone. We have two phases of higher-order functions involved in defining a decorator; they are as follows: At definition time, a decorator function applies a wrapper to a base function and returns the new, wrapped function. The decoration process can do some one-time-only evaluation as part of building the decorated function. Complex default values can be computed, for example. At evaluation time, the wrapping function can (and usually does) evaluate the base function. The wrapping function can pre-process the argument values or post-process the return value (or both). It's also possible that the wrapping function may avoid calling the base function. In the case of managing a cache, for example, the primary reason for wrapping is to avoid expensive calls to the base function. Simple Decorator function Here's an example of a simple decorator: from functools import wraps from typing import Callable, Optional, Any, TypeVar, cast FuncType = Callable[..., Any] F = TypeVar('F', bound=FuncType) def nullable(function: F) -> F: @wraps(function) def null_wrapper(arg: Optional[Any]) -> Optional[Any]: return None if arg is None else function(arg) return cast(F, null_wrapper) We almost always want to use the functools.wraps() function to assure that the decorated function retains the attributes of the original function. Copying the __name__, and __doc__ attributes, for example, assures that the resulting decorated function has the name and docstring of the original function. The resulting composite function, defined as the null_wrapper() function in the definition of the decorator, is also a type of higher-order function that combines the original function, the function() callable object, in an expression that preserves the None values. Within the resulting null_wrapper() function, the original function callable object is not an explicit argument; it is a free variable that will get its value from the context in which the null_wrapper() function is defined. The decorator function's return value is the newly minted function. It will be assigned to the original function's name. It's important that decorators only return functions and that they don't attempt to process data. Decorators use meta-programming: a code that creates a code. The resulting null_wrapper() function, however, will be used to process the real data. Note that the type hints use a feature of a TypeVar to assure that the result of applying the decorator will be a an object that's a type of Callable. The type variable F is bound to the original function's type; the decorator's type hint claims that the resulting function should have the same type as the argument function. A very general decorator will apply to a wide variety of functions, requiring a type variable binding. Creating composite function We can apply our @nullable decorator to create a composite function as follows: @nullable def nlog(x: Optional[float]) -> Optional[float]: return math.log(x) This will create a function, nlog(), which is a null-aware version of the built-in math.log() function. The decoration process returned a version of the null_wrapper() function that invokes the original nlog(). This result will be named nlog(), and will have the composite behavior of the wrapping and the original wrapped function. We can use this composite nlog() function as follows: >>> some_data = [10, 100, None, 50, 60] >>> scaled = map(nlog, some_data) >>> list(scaled) [2.302585092994046, 4.605170185988092, None, 3.912023005428146, 4.0943445622221] We've applied the function to a collection of data values. The None value politely leads to a None result. There was no exception processing involved. This type of example isn't really suitable for unit testing. We'll need to round the values for testing purposes. For this, we'll need a null-aware round() function too. Here's how we can create a null-aware rounding function using decorator notation: @nullable def nround4(x: Optional[float]) -> Optional[float]: return round(x, 4) This function is a partial application of the round() function, wrapped to be null-aware. In some respects, this is a relatively sophisticated bit of functional programming that's readily available to Python programmers. The typing module makes it particularly easy to describe the types of null-aware function and null-aware result, using the Optional type definition. The definition Optional[float] means Union[None, float]; either a None object or a float object may be used. We could also create the null-aware rounding function using the following code: nround4 = nullable(lambda x: round(x, 4)) Note that we didn't use the decorator in front of a function definition. Instead, we applied the decorator to a function defined as a lambda form.  This has the same effect as a decorator in front of a function definition. We can use this round4() function to create a better test case for our nlog() function as follows: >>> some_data = [10, 100, None, 50, 60] >>> scaled = map(nlog, some_data) >>> [nround4(v) for v in scaled] [2.3026, 4.6052, None, 3.912, 4.0943] This result will be independent of any platform considerations. It's very handy for doctest testing. It can be challenging to apply type hints to lambda forms. The following code shows what is required: nround4l: Callable[[Optional[float]], Optional[float]] = ( nullable(lambda x: round(x, 4)) ) The variable nround4l is given a type hint of Callable with an argument list of [Optional[float]] and a return type of Optional[float]. The use of the Callable hint is appropriate only for positional arguments. In cases where there will be keyword arguments or other complexities, see http://mypy.readthedocs.io/en/latest/kinds_of_types.html#extended-callable-types. The @nullable decorator makes an assumption that the decorated function is unary. We would need to revisit this design to create a more general-purpose null-aware decorator that works with arbitrary collections of arguments. If you found this tutorial useful and interested to learn more such techniques, grab the Steven Lott's bestseller, Functional Python Programming. Putting the Fun in Functional Python Why functional programming in Python matters: Interview with best selling author, Steven Lott Expert Python Programming: Interfaces
Read more
  • 0
  • 0
  • 4368

article-image-creating-macros-in-rust-tutorial
Aaron Lazar
23 Aug 2018
14 min read
Save for later

Creating Macros in Rust [Tutorial]

Aaron Lazar
23 Aug 2018
14 min read
Since Rust 1.0 has a great macro system, it allows us to apply some code to multiple types or expressions, as they work by expanding themselves at compile time. This means that when you use a macro, you are effectively writing a lot of code before the actual compilation starts. This has two main benefits, first, the codebase can be easier to maintain by being smaller and reusing code. Second, since macros expand before starting the creation of object code, you can abstract at the syntactic level. In this article, we'll learn how to create our very own macros in Rust. This Rust tutorial is an extract from Rust High Performance, authored by Iban Eguia Moraza. For example, you can have a function like this one: fn add_one(input: u32) -> u32 { input + 1 } This function restricts the input to u32 types and the return type to u32. We could add some more accepted types by using generics, which may accept &u32 if we use the Add trait. Macros allow us to create this kind of code for any element that can be written to the left of the + sign and it will be expanded differently for each type of element, creating a different code for each case. To create a macro, you will need to use a macro built into the language, the macro_rules!{} macro. This macro receives the name of the new macro as a first parameter and a block with the macro code as a second element. The syntax can be a bit complex the first time you see it, but it can be learned quickly. Let's start with a macro that does just the same as the function we saw before: macro_rules! add_one { ($input:expr) => { $input + 1 } } You can now call that macro from your main() function by calling add_one!(integer);. Note that the macro needs to be defined before the first call, even if it's in the same file. It will work with any integer, which wasn't possible with functions. Let's analyze how the syntax works. In the block after the name of the new macro (add_one), we can see two sections. In the first part, on the left of the =>, we see $input:expr inside parentheses. Then, to the right, we see a Rust block where we do the actual addition. The left part works similarly (in some ways) to a pattern match. You can add any combination of characters and then some variables, all of them starting with a dollar sign ($) and showing the type of variable after a colon. In this case, the only variable is the $input variable and it's an expression. This means that you can insert any kind of expression there and it will be written in the code to the right, substituting the variable with the expression. Creating Macro variants As you can see, it's not as complicated as you might think. As I wrote, you can have almost any pattern to the left of the macro_rules!{} side. Not only that, you can also have multiple patterns, as if it were a match statement, so that if one of them matches, it will be the one expanded. Let's see how this works by creating a macro which, depending on how we call it, will add one or two to the given integer: macro_rules! add { {one to $input:expr} => ($input + 1); {two to $input:expr} => ($input + 2); } fn main() { println!("Add one: {}", add!(one to 25/5)); println!("Add two: {}", add!(two to 25/5)); } You can see a couple of clear changes to the macro. First, we swapped braces for parentheses and parentheses for braces in the macro. This is because in a macro, you can use interchangeable braces ({ and }), square brackets ([ and ]), and parentheses (( and )). Not only that, you can use them when calling the macro. You have probably already used the vec![] macro and the format!() macro, and we saw the lazy_static!{} macro in the last chapter. We use brackets and parentheses here just for convention, but we could call the vec!{} or the format![] macros the same way, because we can use braces, brackets, and parentheses in any macro call. The second change was to add some extra text to our left-hand side patterns. We now call our macro by writing the text one to or two to, so I also removed the one redundancy to the macro name and called it add!(). This means that we now call our macro with literal text. That is not valid Rust, but since we are using a macro, we modify the code we are writing before the compiler tries to understand actual Rust code and the generated code is valid. We could add any text that does not end the pattern (such as parentheses or braces) to the pattern. The final change was to add a second possible pattern. We can now add one or two and the only difference will be that the right side of the macro definition must now end with a trailing semicolon for each pattern (the last one is optional) to separate each of the options. A small detail that I also added in the example was when calling the macro in the main() function. As you can see, I could have added one or two to 5, but I wrote 25/5 for a reason. When compiling this code, this will be expanded to 25/5 + 1 (or 2, if you use the second variant). This will later be optimized at compile time, since it will know that 25/5 + 1 is 6, but the compiler will receive that expression, not the final result. The macro system will not calculate the result of the expression; it will simply copy in the resulting code whatever you give to it and then pass it to the next compiler phase. You should be especially careful with this when a macro you are creating calls another macro. They will get expanded recursively, one inside the other, so the compiler will receive a bunch of final Rust code that will need to be optimized. Issues related to this were found in the CLAP crate that we saw in the last chapter, since the exponential expansions were adding a lot of bloat code to their executables. Once they found out that there were too many macro expansions inside the other macros and fixed it, they reduced the size of their binary contributions by more than 50%. Macros allow for an extra layer of customization. You can repeat arguments more than once. This is common, for example, in the vec![] macro, where you create a new vector with information at compile time. You can write something like vec![3, 4, 76, 87];. How does the vec![] macro handle an unspecified number of arguments? Creating Complex macros We can specify that we want multiple expressions in the left-hand side pattern of the macro definition by adding a * for zero or more matches or a + for one or more matches. Let's see how we can do that with a simplified my_vec![] macro: macro_rules! my_vec { ($($x: expr),*) => {{ let mut vector = Vec::new(); $(vector.push($x);)* vector }} } Let's see what is happening here. First, we see that on the left side, we have two variables, denoted by the two $ signs. The first makes reference to the actual repetition. Each comma-separated expression will generate a $x variable. Then, on the right side, we use the various repetitions to push $x to the vector once for every expression we receive. There is another new thing on the right-hand side. As you can see, the macro expansion starts and ends with a double brace instead of using only one. This is because, once the macro gets expanded, it will substitute the given expression for a new expression: the one that gets generated. Since what we want is to return the vector we are creating, we need a new scope where the last sentence will be the value of the scope once it gets executed. You will be able to see it more clearly in the next code snippet. We can call this code with the main() function: fn main() { let my_vector = my_vec![4, 8, 15, 16, 23, 42]; println!("Vector test: {:?}", my_vector); } It will be expanded to this code: fn main() { let my_vector = { let mut vector = Vec::new(); vector.push(4); vector.push(8); vector.push(15); vector.push(16); vector.push(23); vector.push(42); vector }; println!("Vector test: {:?}", my_vector); } As you can see, we need those extra braces to create the scope that will return the vector so that it gets assigned to the my_vector binding. You can have multiple repetition patterns on the left expression and they will be repeated for every use, as needed on the right. macro_rules! add_to_vec { ($( $x:expr; [ $( $y:expr ),* ]);* ) => { &[ $($( $x + $y ),*),* ] } } In this example, the macro can receive one or more $x; [$y1, $y2,...] input. So, for each input, it will have one expression, then a semicolon, then a bracket with multiple sub-expressions separated by a comma, and finally, another bracket and a semicolon. But what does the macro do with this input? Let's check to the right-hand side of it. As you can see, this will create multiple repetitions. We can see that it creates a slice (&[T]) of whatever we feed to it, so all the expressions we use must be of the same type. Then, it will start iterating over all $x variables, one per input group. So if we feed it only one input, it will iterate once for the expression to the left of the semicolon. Then, it will iterate once for every $y expression associated with the $x expression, add them to the + operator, and include the result in the slice. If this was too complex to understand, let's look at an example. Let's suppose we call the macro with 65; [22, 34] as input. In this case, 65 will be $x, and 22, 24, and so on will be $y variables associated with 65. So, the result will be a slice like this: &[65+22, 65+34]. Or, if we calculate the results: &[87, 99]. If, on the other hand, we give two groups of variables by using 65; [22, 34]; 23; [56, 35] as input, in the first iteration, $x will be 65, while in the second one, it will be 23. The $y variables of 64 will be 22 and 34, as before, and the ones associated with 23 will be 56 and 35. This means that the final slice will be &[87, 99, 79, 58], where 87 and 99 work the same way as before and 79 and 58 are the extension of adding 23 to 56 and 23 to 35. This gives you much more flexibility than the functions, but remember, all this will be expanded during compile time, which can make your compilation time much slower and the final codebase larger and slower still if the macro used duplicates too much code. In any case, there is more flexibility to it yet. So far, all variables have been of the expr kind. We have used this by declaring $x:expr and $y:expr but, as you can imagine, there are other kinds of macro variables. The list follows: expr: Expressions that you can write after an = sign, such as 76+4 or if a==1 {"something"} else {"other thing"}. ident: An identifier or binding name, such as foo or bar. path: A qualified path. This will be a path that you could write in a use sentence, such as foo::bar::MyStruct or foo::bar::my_func. ty: A type, such as u64 or MyStruct. It can also be a path to the type. pat: A pattern that you can write at the left side of an = sign or in a match expression, such as Some(t) or (a, b, _). stmt: A full statement, such as a let binding like let a = 43;. block: A block element that can have multiple statements and a possible expression between braces, such as {vec.push(33); vec.len()}. item: What Rust calls items. For example, function or type declarations, complete modules, or trait definitions. meta: A meta element, which you can write inside of an attribute (#[]). For example, cfg(feature = "foo"). tt: Any token tree that will eventually get parsed by a macro pattern, which means almost anything. This is useful for creating recursive macros, for example. As you can imagine, some of these kinds of macro variables overlap and some of them are just more specific than the others. The use will be verified on the right-hand side of the macro, in the expansion, since you might try to use a statement where an expression must be used, even though you might use an identifier too, for example. There are some extra rules, too, as we can see in the Rust documentation (https://doc.rust-lang.org/book/first-edition/macros.html#syntactic-requirements). Statements and expressions can only be followed by =>, a comma, or a semicolon. Types and paths can only be followed by =>, the as or where keywords, or any commas, =, |, ;, :, >, [, or {. And finally, patterns can only be followed by =>, the if or in keywords, or any commas, =, or |. Let's put this in practice by implementing a small Mul trait for a currency type we can create. This is an adapted example of some work we did when creating the Fractal Credits digital currency. In this case, we will look to the implementation of the Amount type (https://github.com/FractalGlobal/utils-rs/blob/49955ead9eef2d9373cc9386b90ac02b4d5745b4/src/amount.rs#L99-L102), which represents a currency amount. Let's start with the basic type definition: #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Amount { value: u64, } This amount will be divisible by up to three decimals, but it will always be an exact value. We should be able to add an Amount to the current Amount, or to subtract it. I will not explain these trivial implementations, but there is one implementation where macros can be of great help. We should be able to multiply the amount by any positive integer, so we should implement the Mul trait for u8, u16, u32, and u64 types. Not only that, we should be able to implement the Div and the Rem traits, but I will leave those out, since they are a little bit more complex. You can check them in the implementation linked earlier. The only thing the multiplication of an Amount with an integer should do is to multiply the value by the integer given. Let's see a simple implementation for u8: use std::ops::Mul; impl Mul<u8> for Amount { type Output = Self; fn mul(self, rhs: u8) -> Self::Output { Self { value: self.value * rhs as u64 } } } impl Mul<Amount> for u8 { type Output = Amount; fn mul(self, rhs: Amount) -> Self::Output { Self::Output { value: self as u64 * rhs.value } } } As you can see, I implemented it both ways so that you can put the Amount to the left and to the right of the multiplication. If we had to do this for all integers, it would be a big waste of time and code. And if we had to modify one of the implementations (especially for Rem functions), it would be troublesome to do it in multiple code points. Let's use macros to help us. We can define a macro, impl_mul_int!{}, which will receive a list of integer types and then implement the Mul trait back and forward between all of them and the Amount type. Let's see: macro_rules! impl_mul_int { ($($t:ty)*) => ($( impl Mul<$t> for Amount { type Output = Self; fn mul(self, rhs: $t) -> Self::Output { Self { value: self.value * rhs as u64 } } } impl Mul<Amount> for $t { type Output = Amount; fn mul(self, rhs: Amount) -> Self::Output { Self::Output { value: self as u64 * rhs.value } } } )*) } impl_mul_int! { u8 u16 u32 u64 usize } As you can see, we specifically ask for the given elements to be types and then we implement the trait for all of them. So, for any code that you want to implement for multiple types, you might as well try this approach, since it will save you from writing a lot of code and it will make it more maintainable. If you found this article useful and would like to learn more such tips, head on over to pick up the book, Rust High Performance, authored by Iban Eguia Moraza. Perform Advanced Programming with Rust Rust 1.28 is here with global allocators, nonZero types and more Eclipse IDE's Photon release will support Rust
Read more
  • 0
  • 0
  • 19438
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $15.99/month. Cancel anytime
article-image-train-convolutional-neural-network-in-keras-improve-with-data-augmentation
Amey Varangaonkar
23 Aug 2018
10 min read
Save for later

Train a convolutional neural network in Keras and improve it with data augmentation [Tutorial]

Amey Varangaonkar
23 Aug 2018
10 min read
In this article, we will see how convolutional layers work and how to use them. We will also see how you can build your own convolutional neural network in Keras to build better, more powerful deep neural networks and solve computer vision problems. We will also see how we can improve this network using data augmentation. For a better understanding of the concepts, we will be taking a well-known dataset CIFAR-10. This dataset was created by Alex Krizhevsky, Vinod Nair, and Geoffrey Hinton. The following article has been taken from the book Deep Learning Quick Reference, written by Mike Bernico.  Adding inputs to the network The CIFAR-10 dataset is made up of 60,000 32 x 32 color images that belong to 10 classes, with 6,000 images per class. We'll be using 50,000 images as a training set, 5,000 images as a validation set, and 5,000 images as a test set. The input tensor layer for the convolutional neural network will be (N, 32, 32, 3), which we will pass to the build_network function. The following code is used to build the network: def build_network(num_gpu=1, input_shape=None): inputs = Input(shape=input_shape, name="input") Getting the output The output of this model will be a class prediction, from 0-9. We will use a 10-node softmax.  We will use the following code to define the output: output = Dense(10, activation="softmax", name="softmax")(d2) Cost function and metrics Earlier, we used categorical cross-entropy as the loss function for a multi-class classifier.  This is just another multiclass classifier and we can continue using categorical cross-entropy as our loss function, and accuracy as a metric. We've moved on to using images as input, but luckily our cost function and metrics remain unchanged. Working with convolutional layers We're going to use two convolutional layers, with batch normalization, and max pooling. This is going to require us to make quite a few choices, which of course we could choose to search as hyperparameters later. It's always better to get something working first though. As the popular computer scientist and mathematician Donald Knuth would say, premature optimization is the root of all evil. We will use the following code snippet to define the two convolutional blocks: # convolutional block 1 conv1 = Conv2D(64, kernel_size=(3,3), activation="relu", name="conv_1")(inputs) batch1 = BatchNormalization(name="batch_norm_1")(conv1) pool1 = MaxPooling2D(pool_size=(2, 2), name="pool_1")(batch1) # convolutional block 2 conv2 = Conv2D(32, kernel_size=(3,3), activation="relu", name="conv_2")(pool1) batch2 = BatchNormalization(name="batch_norm_2")(conv2) pool2 = MaxPooling2D(pool_size=(2, 2), name="pool_2")(batch2) So, clearly, we have two convolutional blocks here, that consist of a convolutional layer, a batch normalization layer, and a pooling layer. In the first block, I'm using 64 3 x 3 filters with relu activations. I'm using valid (no) padding and a stride of 1. Batch normalization doesn't require any parameters and it isn't really trainable. The pooling layer is using 2 x 2 pooling windows, valid padding, and a stride of 2 (the dimension of the window). The second block is very much the same; however, I'm halving the number of filters to 32. While there are many knobs we could turn in this architecture, the one I would tune first is the kernel size of the convolutions. Kernel size tends to be an important choice. In fact, some modern neural network architectures such as Google's inception, allow us to use multiple filter sizes in the same convolutional layer. Getting the fully connected layers After two rounds of convolution and pooling, our tensors have gotten relatively small and deep. After pool_2, the output dimension is (n, 6, 6, 32). We have, in these convolutional layers, hopefully extracted relevant image features that this 6 x 6 x 32 tensor represents. To classify images, using these features, we will connect this tensor to a few fully connected layers, before we go to our final output layer. In this example, I'll use a 512-neuron fully connected layer, a 256-neuron fully connected layer, and finally, the 10-neuron output layer. I'll also be using dropout to help prevent overfitting, but only a very little bit! The code for this process is given as follows for your reference: from keras.layers import Flatten, Dense, Dropout # fully connected layers flatten = Flatten()(pool2) fc1 = Dense(512, activation="relu", name="fc1")(flatten) d1 = Dropout(rate=0.2, name="dropout1")(fc1) fc2 = Dense(256, activation="relu", name="fc2")(d1) d2 = Dropout(rate=0.2, name="dropout2")(fc2) I haven't previously mentioned the flatten layer above. The flatten layer does exactly what its name suggests. It flattens the n x 6 x 6 x 32 tensor into an n x 1152 vector. This will serve as an input to the fully connected layers. Working with multi-GPU models in Keras Many cloud computing platforms can provision instances that include multiple GPUs. As our models grow in size and complexity you might want to be able to parallelize the workload across multiple GPUs. This can be a somewhat involved process in native TensorFlow, but in Keras, it's just a function call. Build your model, as normal, as shown in the following code: model = Model(inputs=inputs, outputs=output) Then, we just pass that model to keras.utils.multi_gpu_model, with the help of the following code: model = multi_gpu_model(model, num_gpu) In this example, num_gpu is the number of GPUs we want to use. Training the model Putting the model together, and incorporating our new cool multi-GPU feature, we come up with the following architecture: def build_network(num_gpu=1, input_shape=None): inputs = Input(shape=input_shape, name="input") # convolutional block 1 conv1 = Conv2D(64, kernel_size=(3,3), activation="relu", name="conv_1")(inputs) batch1 = BatchNormalization(name="batch_norm_1")(conv1) pool1 = MaxPooling2D(pool_size=(2, 2), name="pool_1")(batch1) # convolutional block 2 conv2 = Conv2D(32, kernel_size=(3,3), activation="relu", name="conv_2")(pool1) batch2 = BatchNormalization(name="batch_norm_2")(conv2) pool2 = MaxPooling2D(pool_size=(2, 2), name="pool_2")(batch2) # fully connected layers flatten = Flatten()(pool2) fc1 = Dense(512, activation="relu", name="fc1")(flatten) d1 = Dropout(rate=0.2, name="dropout1")(fc1) fc2 = Dense(256, activation="relu", name="fc2")(d1) d2 = Dropout(rate=0.2, name="dropout2")(fc2) # output layer output = Dense(10, activation="softmax", name="softmax")(d2) # finalize and compile model = Model(inputs=inputs, outputs=output) if num_gpu > 1: model = multi_gpu_model(model, num_gpu) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=["accuracy"]) return model We can use this to build our model: model = build_network(num_gpu=1, input_shape=(IMG_HEIGHT, IMG_WIDTH, CHANNELS)) And then we can fit it, as you'd expect: model.fit(x=data["train_X"], y=data["train_y"], batch_size=32, epochs=200, validation_data=(data["val_X"], data["val_y"]), verbose=1, callbacks=callbacks) As we train this model, you will notice that overfitting is an immediate concern. Even with a relatively modest two convolutional layers, we're already overfitting a bit. You can see the effects of overfitting from the following graphs: It's no surprise, 50,000 observations is not a lot of data, especially for a computer vision problem. In practice, computer vision problems benefit from very large datasets. In fact, Chen Sun showed that additional data tends to help computer vision models linearly with the log of the data volume in https://arxiv.org/abs/1707.02968. Unfortunately, we can't really go find more data in this case. But maybe we can make some. Let's talk about data augmentation next. Using data augmentation Data augmentation is a technique where we apply transformations to an image and use both the original image and the transformed images to train on. Imagine we had a training set with a cat in it: If we were to apply a horizontal flip to this image, we'd get something that looks like this: This is exactly the same image, of course, but we can use both the original and transformation as training examples. This isn't quite as good as two separate cats in our training set; however, it does allow us to teach the computer that a cat is a cat regardless of the direction it's facing. In practice, we can do a lot more than just a horizontal flip. We can vertically flip, when it makes sense, shift, and randomly rotate images as well. This allows us to artificially amplify our dataset and make it seem bigger than it is. Of course, you can only push this so far, but it's a very powerful tool in the fight against overfitting when little data exists. What is the Keras ImageDataGenerator? Not so long ago, the only way to do image augmentation was to code up the transforms and apply them randomly to the training set, saving the transformed images to disk as we went (uphill, both ways, in the snow). Luckily for us, Keras now provides an ImageDataGenerator class that can apply transformations on the fly as we train, without having to hand code the transformations. We can create a data generator object from ImageDataGenerator by instantiating it like this: def create_datagen(train_X): data_generator = ImageDataGenerator( rotation_range=20, width_shift_range=0.02, height_shift_range=0.02, horizontal_flip=True) data_generator.fit(train_X) return data_generator In this example, I'm using both shifts, rotation, and horizontal flips. I'm using only very small shifts. Through experimentation, I found that larger shifts were too much and my network wasn't actually able to learn anything. Your experience will vary as your problem does, but I would expect larger images to be more tolerant of shifting. In this case, we're using 32 pixel images, which are quite small. Training with a generator If you haven't used a generator before, it works like an iterator. Every time you call the ImageDataGenerator .flow() method, it will produce a new training minibatch, with random transformations applied to the images it was fed. The Keras Model class comes with a .fit_generator() method that allows us to fit with a generator rather than a given dataset: model.fit_generator(data_generator.flow(data["train_X"], data["train_y"], batch_size=32), steps_per_epoch=len(data["train_X"]) // 32, epochs=200, validation_data=(data["val_X"], data["val_y"]), verbose=1, callbacks=callbacks) Here, we've replaced the traditional x and y parameters with the generator. Most importantly, notice the steps_per_epoch parameter. You can sample with replacement any number of times from the training set, and you can apply random transformations each time. This means that we can use more mini batches each epoch than we have data. Here, I'm going to only sample as many batches as I have observations, but that isn't required. We can and should push this number higher if we can. Before we wrap things up, let's look at how beneficial image augmentation is in this case: As you can see, just a little bit of image augmentation really helped us out. Not only is our overall accuracy higher, but our network is overfitting much slower. If you have a computer vision problem with just a little bit of data, image augmentation is something you'll want to do. We saw the benefits and ease of training a convolutional neural network from scratch using Keras and then improving that network using data augmentation. If you found the above article to be useful, make sure you check out the book Deep Learning Quick Reference for more information on modeling and training various different types of deep neural networks with ease and efficiency. Top 5 Deep Learning Architectures CapsNet: Are Capsule networks the antidote for CNNs kryptonite? What is a CNN?
Read more
  • 0
  • 0
  • 7216

article-image-shared-pointers-in-rust-challenges-solutions
Aaron Lazar
22 Aug 2018
8 min read
Save for later

Working with Shared pointers in Rust: Challenges and Solutions [Tutorial]

Aaron Lazar
22 Aug 2018
8 min read
One of Rust's most criticized problem is that it's difficult to develop an application with shared pointers. It's true that due to Rust's memory safety guarantees, it might be difficult to develop those kind of algorithms, but as we will see now, the standard library gives us types we can use to safely allow that behavior. In this article, we'll understand how to overcome the issue of shared pointers in Rust to increase efficiency. This article is an extract from Rust High Performance, authored by Iban Eguia Moraza. Overcoming issue with cell module The standard Rust library has one interesting module, the std::cell module, that allows us to use objects with interior mutability. This means that we can have an immutable object and still mutate it by getting a mutable borrow to the underlying data. This, of course, would not comply with the mutability rules we saw before, but the cells make sure this works by checking the borrows at runtime or by doing copies of the underlying data. Cells Let's start with the basic Cell structure. A Cell will contain a mutable value, but it can be mutated without having a mutable Cell. It has mainly three interesting methods: set(), swap(), and replace(). The first allows us to set the contained value, replacing it with a new value. The previous structure will be dropped (the destructor will run). That last bit is the only difference with the replace() method. In the replace() method, instead of dropping the previous value, it will be returned. The swap() method, on the other hand, will take another Cell and swap the values between the two. All this without the Cell needing to be mutable. Let's see it with an example: use std::cell::Cell; #[derive(Copy, Clone)] struct House { bedrooms: u8, } impl Default for House { fn default() -> Self { House { bedrooms: 1 } } } fn main() { let my_house = House { bedrooms: 2 }; let my_dream_house = House { bedrooms: 5 }; let my_cell = Cell::new(my_house); println!("My house has {} bedrooms.", my_cell.get().bedrooms); my_cell.set(my_dream_house); println!("My new house has {} bedrooms.", my_cell.get().bedrooms); let my_new_old_house = my_cell.replace(my_house); println!( "My house has {} bedrooms, it was better with {}", my_cell.get().bedrooms, my_new_old_house.bedrooms ); let my_new_cell = Cell::new(my_dream_house); my_cell.swap(&my_new_cell); println!( "Yay! my current house has {} bedrooms! (my new house {})", my_cell.get().bedrooms, my_new_cell.get().bedrooms ); let my_final_house = my_cell.take(); println!( "My final house has {} bedrooms, the shared one {}", my_final_house.bedrooms, my_cell.get().bedrooms ); } As you can see in the example, to use a Cell, the contained type must be Copy. If the contained type is not Copy, you will need to use a RefCell, which we will see next. Continuing with this Cell example, as you can see through the code, the output will be the following: So we first create two houses, we select one of them as the current one, and we keep mutating the current and the new ones. As you might have seen, I also used the take() method, only available for types implementing the Default trait. This method will return the current value, replacing it with the default value. As you can see, you don't really mutate the value inside, but you replace it with another value. You can either retrieve the old value or lose it. Also, when using the get() method, you get a copy of the current value, and not a reference to it. That's why you can only use elements implementing Copy with a Cell. This also means that a Cell does not need to dynamically check borrows at runtime. RefCell RefCell is similar to Cell, except that it accepts non-Copy data. This also means that when modifying the underlying object, it cannot simply copy it when returning it, it will need to return references. The same way, when you want to mutate the object inside, it will return a mutable reference. This only works because it will dynamically check at runtime whether a borrow exists before returning a mutable borrow, or the other way around, and if it does, the thread will panic. Instead of using the get() method as in Cell, RefCell has two methods to get the underlying data: borrow() and borrow_mut(). The first will get a read-only borrow, and you can have as many immutable borrows in a scope. The second one will return a read-write borrow, and you will only be able to have one in scope to follow the mutability rules. If you try to do a borrow_mut() after a borrow() in the same scope, or a borrow() after a borrow_mut(), the thread will panic. There are two non-panicking alternatives to these borrows: try_borrow() and try_borrow_mut(). These two will try to borrow the data (the first read-only and the second read/write), and if there are incompatible borrows present, they will return a Result::Err, so that you can handle the error without panicking. Both Cell and RefCell have a get_mut() method, that will get a mutable reference to the element inside, but it requires the Cell / RefCell to be mutable, so it doesn't make much sense if you need the Cell / RefCell to be immutable. Nevertheless, if in a part of the code you can actually have a mutable Cell / RefCell, you should use this method to change the contents, since it will check all rules statically at compile time, without runtime overhead. Interestingly enough, RefCell does not return a plain reference to the underlying data when we call borrow() or borrow_mut(). You would expect them to return &T and &mut T (where T is the wrapped element). Instead, they will return a Ref and a RefMut, respectively. This is to safely wrap the reference inside, so that the lifetimes get correctly calculated by the compiler without requiring references to live for the whole lifetime of the RefCell. They implement Deref into references, though, so thanks to Rust's Deref coercion, you can use them as references. Overcoming issue with rc module The std::rc module contains reference-counted pointers that can be used in single-threaded applications. They have very little overhead, thanks to counters not being atomic counters, but this means that using them in multithreaded applications could cause data races. Thus, Rust will stop you from sending them between threads at compile time. There are two structures in this module: Rc and Weak. An Rc is an owning pointer to the heap. This means that it's the same as a Box, except that it allows for reference-counted pointers. When the Rc goes out of scope, it will decrease by 1 the number of references, and if that count is 0, it will drop the contained object. Since an Rc is a shared reference, it cannot be mutated, but a common pattern is to use a Cell or a RefCell inside the Rc to allow for interior mutability. Rc can be downgraded to a Weak pointer, that will have a borrowed reference to the heap. When an Rc drops the value inside, it will not check whether there are Weak pointers to it. This means that a Weak pointer will not always have a valid reference, and therefore, for safety reasons, the only way to check the value of the Weak pointer is to upgrade it to an Rc, which could fail. The upgrade() method will return None if the reference has been dropped. Let's check all this by creating an example binary tree structure: use std::cell::RefCell; use std::rc::{Rc, Weak}; struct Tree<T> { root: Node<T>, } struct Node<T> { parent: Option<Weak<Node<T>>>, left: Option<Rc<RefCell<Node<T>>>>, right: Option<Rc<RefCell<Node<T>>>>, value: T, } In this case, the tree will have a root node, and each of the nodes can have up to two children. We call them left and right, because they are usually represented as trees with one child on each side. Each node has a pointer to one of the children, and it owns the children nodes. This means that when a node loses all references, it will be dropped, and with it, its children. Each child has a pointer to its parent. The main issue with this is that, if the child has an Rc pointer to its parent, it will never drop. This is a circular dependency, and to avoid it, the pointer to the parent will be a Weak pointer. So, you've finally understood how Rust manages shared pointers for complex structures, where the Rust borrow checker can make your coding experience much more difficult. If you found this article useful and would like to learn more such tips, head over to pick up the book, Rust High Performance, authored by Iban Eguia Moraza. Perform Advanced Programming with Rust Rust 1.28 is here with global allocators, nonZero types and more Say hello to Sequoia: a new Rust based OpenPGP library to secure your apps
Read more
  • 0
  • 0
  • 9103

article-image-generative-adversarial-networks-using-keras
Amey Varangaonkar
21 Aug 2018
12 min read
Save for later

Generative Adversarial Networks: Generate images using Keras GAN [Tutorial]

Amey Varangaonkar
21 Aug 2018
12 min read
You might have worked with the popular MNIST dataset before - but in this article, we will be generating new MNIST-like images with a Keras GAN. It can take a very long time to train a GAN; however, this problem is small enough to run on most laptops in a few hours, which makes it a great example. The following excerpt is taken from the book Deep Learning Quick Reference, authored by Mike Bernico. The network architecture that we will be using here has been found by, and optimized by, many folks, including the authors of the DCGAN paper and people like Erik Linder-Norén, who's excellent collection of GAN implementations called Keras GAN served as the basis of the code we used here. Loading the MNIST dataset The MNIST dataset consists of 60,000 hand-drawn numbers, 0 to 9. Keras provides us with a built-in loader that splits it into 50,000 training images and 10,000 test images. We will use the following code to load the dataset: from keras.datasets import mnist def load_data(): (X_train, _), (_, _) = mnist.load_data() X_train = (X_train.astype(np.float32) - 127.5) / 127.5 X_train = np.expand_dims(X_train, axis=3) return X_train As you probably noticed, We're not returning any of the labels or the testing dataset. We're only going to use the training dataset. The labels aren't needed because the only labels we will be using are 0 for fake and 1 for real. These are real images, so they will all be assigned a label of 1 at the discriminator. Building the generator The generator uses a few new layers that we will talk about in this section. First, take a chance to skim through the following code: def build_generator(noise_shape=(100,)): input = Input(noise_shape) x = Dense(128 * 7 * 7, activation="relu")(input) x = Reshape((7, 7, 128))(x) x = BatchNormalization(momentum=0.8)(x) x = UpSampling2D()(x) x = Conv2D(128, kernel_size=3, padding="same")(x) x = Activation("relu")(x) x = BatchNormalization(momentum=0.8)(x) x = UpSampling2D()(x) x = Conv2D(64, kernel_size=3, padding="same")(x) x = Activation("relu")(x) x = BatchNormalization(momentum=0.8)(x) x = Conv2D(1, kernel_size=3, padding="same")(x) out = Activation("tanh")(x) model = Model(input, out) print("-- Generator -- ") model.summary() return model We have not previously used the UpSampling2D layer. This layer will take increases in the rows and columns of the input tensor, leaving the channels unchanged. It does this by repeating the values in the input tensor. By default, it will double the input. If we give an UpSampling2D layer a 7 x 7 x 128 input, it will give us a 14 x 14 x 128 output. Typically when we build a CNN, we start with an image that is very tall and wide and uses convolutional layers to get a tensor that's very deep but less tall and wide. Here we will do the opposite. We'll use a dense layer and a reshape to start with a 7 x 7 x 128 tensor and then, after doubling it twice, we'll be left with a 28 x 28 tensor. Since we need a grayscale image, we can use a convolutional layer with a single unit to get a 28 x 28 x 1 output. This sort of generator arithmetic is a little off-putting and can seem awkward at first but after a few painful hours, you will get the hang of it! Building the discriminator The discriminator is really, for the most part, the same as any other CNN. Of course, there are a few new things that we should talk about. We will use the following code to build the discriminator: def build_discriminator(img_shape): input = Input(img_shape) x =Conv2D(32, kernel_size=3, strides=2, padding="same")(input) x = LeakyReLU(alpha=0.2)(x) x = Dropout(0.25)(x) x = Conv2D(64, kernel_size=3, strides=2, padding="same")(x) x = ZeroPadding2D(padding=((0, 1), (0, 1)))(x) x = (LeakyReLU(alpha=0.2))(x) x = Dropout(0.25)(x) x = BatchNormalization(momentum=0.8)(x) x = Conv2D(128, kernel_size=3, strides=2, padding="same")(x) x = LeakyReLU(alpha=0.2)(x) x = Dropout(0.25)(x) x = BatchNormalization(momentum=0.8)(x) x = Conv2D(256, kernel_size=3, strides=1, padding="same")(x) x = LeakyReLU(alpha=0.2)(x) x = Dropout(0.25)(x) x = Flatten()(x) out = Dense(1, activation='sigmoid')(x) model = Model(input, out) print("-- Discriminator -- ") model.summary() return model First, you might notice the oddly shaped zeroPadding2D() layer. After the second convolution, our tensor has gone from 28 x 28 x 3 to 7 x 7 x 64. This layer just gets us back into an even number, adding zeros on one side of both the rows and columns so that our tensor is now 8 x 8 x 64. More unusual is the use of both batch normalization and dropout. Typically, these two layers are not used together; however, in the case of GANs, they do seem to benefit the network. Building the stacked model Now that we've assembled both the generator and the discriminator, we need to assemble a third model that is the stack of both models together that we can use for training the generator given the discriminator loss. To do that we can just create a new model, this time using the previous models as layers in the new model, as shown in the following code: discriminator = build_discriminator(img_shape=(28, 28, 1)) generator = build_generator() z = Input(shape=(100,)) img = generator(z) discriminator.trainable = False real = discriminator(img) combined = Model(z, real) Notice that we're setting the discriminator's training attribute to False before building the model. This means that for this model we will not be updating the weights of the discriminator during backpropagation. We will freeze these weights and only move the generator weights with the stack. The discriminator will be trained separately. Now that all the models are built, they need to be compiled, as shown in the following code: gen_optimizer = Adam(lr=0.0002, beta_1=0.5) disc_optimizer = Adam(lr=0.0002, beta_1=0.5) discriminator.compile(loss='binary_crossentropy', optimizer=disc_optimizer, metrics=['accuracy']) generator.compile(loss='binary_crossentropy', optimizer=gen_optimizer) combined.compile(loss='binary_crossentropy', optimizer=gen_optimizer) If you'll notice, we're creating two custom Adam optimizers. This is because many times we will want to change the learning rate for only the discriminator or generator, slowing one or the other down so that we end up with a stable GAN where neither is overpowering the other. You'll also notice that we're using beta_1 = 0.5. This is a recommendation from the original DCGAN paper that we've carried forward and also had success with. A learning rate of 0.0002 is a good place to start as well, and was found in the original DCGAN paper. The training loop We have previously had the luxury of calling .fit() on our model and letting Keras handle the painful process of breaking the data apart into mini batches and training for us. Unfortunately, because we need to perform the separate updates for the discriminator and the stacked model together for a single batch we're going to have to do things the old-fashioned way, with a few loops. This is how things used to be done all the time, so while it's perhaps a little more work, it does admittedly leave me feeling nostalgic. The following code illustrates the training technique: num_examples = X_train.shape[0] num_batches = int(num_examples / float(batch_size)) half_batch = int(batch_size / 2) for epoch in range(epochs + 1): for batch in range(num_batches): # noise images for the batch noise = np.random.normal(0, 1, (half_batch, 100)) fake_images = generator.predict(noise) fake_labels = np.zeros((half_batch, 1)) # real images for batch idx = np.random.randint(0, X_train.shape[0], half_batch) real_images = X_train[idx] real_labels = np.ones((half_batch, 1)) # Train the discriminator (real classified as ones and generated as zeros) d_loss_real = discriminator.train_on_batch(real_images, real_labels) d_loss_fake = discriminator.train_on_batch(fake_images, fake_labels) d_loss = 0.5 * np.add(d_loss_real, d_loss_fake) noise = np.random.normal(0, 1, (batch_size, 100)) # Train the generator g_loss = combined.train_on_batch(noise, np.ones((batch_size, 1))) # Plot the progress print("Epoch %d Batch %d/%d [D loss: %f, acc.: %.2f%%] [G loss: %f]" % (epoch,batch, num_batches, d_loss[0], 100 * d_loss[1], g_loss)) if batch % 50 == 0: save_imgs(generator, epoch, batch) There is a lot going on here, to be sure. As before, let's break it down block by block. First, let's see the code to generate noise vectors: noise = np.random.normal(0, 1, (half_batch, 100)) fake_images = generator.predict(noise) fake_labels = np.zeros((half_batch, 1)) This code is generating a matrix of noise vectors called z) and sending it to the generator. It's getting a set of generated images back, which we're calling fake images. We will use these to train the discriminator, so the labels we want to use are 0s, indicating that these are in fact generated images. Note that the shape here is half_batch x 28 x 28 x 1. The half_batch is exactly what you think it is. We're creating half a batch of generated images because the other half of the batch will be real data, which we will assemble next. To get our real images, we will generate a random set of indices across X_train and use that slice of X_train as our real images, as shown in the following code: idx = np.random.randint(0, X_train.shape[0], half_batch) real_images = X_train[idx] real_labels = np.ones((half_batch, 1)) Yes, we are sampling with replacement in this case. It does work out but it's probably not the best way to implement minibatch training. It is, however, probably the easiest and most common. Since we are using these images to train the discriminator, and because they are real images, we will assign them 1s as labels, rather than 0s. Now that we have our discriminator training set assembled, we will update the discriminator. Also, note that we aren't using the soft labels. That's because we want to keep things as easy as they can be to understand. Luckily the network doesn't require them in this case. We will use the following code to train the discriminator: # Train the discriminator (real classified as ones and generated as zeros) d_loss_real = discriminator.train_on_batch(real_images, real_labels) d_loss_fake = discriminator.train_on_batch(fake_images, fake_labels) d_loss = 0.5 * np.add(d_loss_real, d_loss_fake) Notice that here we're using the discriminator's train_on_batch() method. The train_on_batch() method does exactly one round of forward and backward propagation. Every time we call it, it updates the model once from the model's previous state. Also, notice that we're making the update for the real images and fake images separately. This is advice that is given on the GAN hack Git we had previously referenced in the Generator architecture section. Especially in the early stages of training, when real images and fake images are from radically different distributions, batch normalization will cause problems with training if we were to put both sets of data in the same update. Now that the discriminator has been updated, it's time to update the generator. This is done indirectly by updating the combined stack, as shown in the following code: noise = np.random.normal(0, 1, (batch_size, 100)) g_loss = combined.train_on_batch(noise, np.ones((batch_size, 1))) To update the combined model, we create a new noise matrix, and this time it will be as large as the entire batch. We will use that as an input to the stack, which will cause the generator to generate an image and the discriminator to evaluate that image. Finally, we will use the label of 1 because we want to backpropagate the error between a real image and the generated image. Lastly, the training loop reports the discriminator and generator loss at the epoch/batch and then, every 50 batches, of every epoch we will use save_imgs to generate example images and save them to disk, as shown in the following code: print("Epoch %d Batch %d/%d [D loss: %f, acc.: %.2f%%] [G loss: %f]" % (epoch,batch, num_batches, d_loss[0], 100 * d_loss[1], g_loss)) if batch % 50 == 0: save_imgs(generator, epoch, batch) The save_imgs function uses the generator to create images as we go, so we can see the fruits of our labor. We will use the following code to define save_imgs: def save_imgs(generator, epoch, batch): r, c = 5, 5 noise = np.random.normal(0, 1, (r * c, 100)) gen_imgs = generator.predict(noise) gen_imgs = 0.5 * gen_imgs + 0.5 fig, axs = plt.subplots(r, c) cnt = 0 for i in range(r): for j in range(c): axs[i, j].imshow(gen_imgs[cnt, :, :, 0], cmap='gray') axs[i, j].axis('off') cnt += 1 fig.savefig("images/mnist_%d_%d.png" % (epoch, batch)) plt.close() It uses only the generator by creating a noise matrix and retrieving an image matrix in return. Then, using matplotlib.pyplot, it saves those images to disk in a 5 x 5 grid. Performing model evaluation Good is somewhat subjective when you're building a deep neural network to create images.  Let's take a look at a few examples of the training process, so you can see for yourself how the GAN begins to learn to generate MNIST. Here's the network at the very first batch of the very first epoch. Clearly, the generator doesn't really know anything about generating MNIST at this point; it's just noise, as shown in the following image: But just 50 batches in, something is happening, as you can see from the following image: And after 200 batches of epoch 0 we can almost see numbers, as you can see from the following image: And here's our generator after one full epoch. These generated numbers look pretty good, and we can see how the discriminator might be fooled by them. At this point, we could probably continue to improve a little bit, but it looks like our GAN has worked as the computer is generating some pretty convincing MNIST digits, as shown in the following image: Thus, we see the power of GANs in action when it comes to image generation using the Keras library. If you found the above article to be useful, make sure you check out our book Deep Learning Quick Reference, for more such interesting coverage of popular deep learning concepts and their practical implementation. Keras 2.2.0 releases! 2 ways to customize your deep learning models with Keras How to build Deep convolutional GAN using TensorFlow and Keras
Read more
  • 0
  • 3
  • 18128

article-image-implementing-dependency-injection-in-spring-tutorial
Natasha Mathur
21 Aug 2018
9 min read
Save for later

Implementing Dependency Injection in Spring [Tutorial]

Natasha Mathur
21 Aug 2018
9 min read
Spring is a lightweight and open source enterprise framework created way back in 2003. Modularity is the heart of the Spring framework. Because of this, Spring can be used from the presentation layer to the persistence layer. The good thing is, Spring doesn't force you to use Spring in all layers. For example, if you use Spring in the persistence layer, you are free to use any other framework in the presentation of the controller layer. In this article we will look at implementing Dependency Injection (DI) in Spring Java application. This tutorial is an excerpt taken from the book  'Java 9 Dependency Injection', written by Krunal Patel, Nilang Patel. Spring is a POJO-based framework; a servlet container is suffice to run your application and a fully-fledged application server is not required. DI is a process of providing the dependent objects to other objects that need it. In Spring, the container supplies the dependencies. The flow of creating and managing the dependencies is inverted from client to container. That is the reason we call it an IoC container. A Spring IoC container uses the Dependency Injection (DI) mechanism to provide the dependency at runtime.  Now we'll talk about how we can implement the constructor and setter-based DI through Spring's IoC container. Implementing Constructor-based DI Constructor-based dependency is generally used where you want to pass mandatory dependencies before the object is instantiated. It's provided by a container through a constructor with different arguments, and each represents dependency. When a container starts, it checks whether any constructor-based DI is defined for <bean>. It will create the dependency objects first, and then pass them to the current object's constructor. We will understand this by taking the classic example of using logging. It is good practice to put the log statement at various places in the code to trace the flow of execution. Let's say you have an EmployeeService class where you need to put a log in each of its methods. To achieve separation of concern, you put the log functionality in a separated class called Logger. To make sure the EmployeeService and Logger are independent and loosely coupled, you need to inject the Logger object into the EmployeeService object. Let's see how to achieve this by constructor-based injection: public class EmployeeService { private Logger log; //Constructor public EmployeeService(Logger log) { this.log = log; } //Service method. public void showEmployeeName() { log.info("showEmployeeName method is called ...."); log.debug("This is Debuggin point"); log.error("Some Exception occured here ..."); } } public class Logger { public void info(String msg){ System.out.println("Logger INFO: "+msg); } public void debug(String msg){ System.out.println("Logger DEBUG: "+msg); } public void error(String msg){ System.out.println("Logger ERROR: "+msg); } } public class DIWithConstructorCheck { public static void main(String[] args) { ApplicationContext springContext = new ClassPathXmlApplicationContext("application-context.xml"); EmployeeService employeeService = (EmployeeService) springContext.getBean("employeeService"); employeeService.showEmployeeName(); } } As per the preceding code, when these objects are configured with Spring, the EmployeeService object expects the Spring container to inject the object of Logger through the constructor. To achieve this, you need to set the configuration metadata as per the following snippet: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- All your bean and its configuration metadata goes here --> <bean id="employeeService" class="com.packet.spring.constructor.di.EmployeeService"> <constructor-arg ref="logger"/> </bean> <bean id="logger" class="com.packet.spring.constructor.di.Logger"> </bean> </beans> In the preceding configuration, the Logger bean is injected into the employee bean through the constructor-arg element. It has a ref attribute, which is used to point to other beans with a matching id value.  This configuration instructs Spring to pass the object of Logger into the constructor of the EmployeeService bean. You can put the <bean> definition in any order here. Spring will create the objects of <bean> based on need, and not as per the order they are defined here. For more than one constructor argument, you can pass additional <constructor-arg> elements. The order is not important as far as the object type (class attribute of referred bean) is not ambiguous. Spring also supports DI with primitive constructor arguments. Spring provides the facility to pass the primitive values in a constructor from an application context (XML) file. Let's say you want to create an object of the Camera class with a default value, as per the following snippet: public class Camera { private int resolution; private String mode; private boolean smileShot; //Constructor. public Camera(int resolution, String mode, boolean smileShot) { this.resolution = resolution; this.mode = mode; this.smileShot = smileShot; } //Public method public void showSettings() { System.out.println("Resolution:"+resolution+"px mode:"+mode+" smileShot:"+smileShot); } } The Camera class has three properties: resolution, mode, and smileShot. Its constructor takes three primitive arguments to create a camera object with default values. You need to give configuration metadata in the following way so that Spring can create instances of the Camera object with default primitive values: <bean id="camera" class="com.packet.spring.constructor.di.Camera"> <constructor-arg type="int" value="12" /> <constructor-arg type="java.lang.String" value="normal" /> <constructor-arg type="boolean" value="false" /> </bean> We pass three <constructor-arg> elements under <bean>, corresponding to each constructor argument. Since these are primitive, Spring has no idea about its type while passing the value. So, we need to explicitly pass the type attribute, which defines the type of primitive constructor argument. In case of primitive also, there is no fixed order to pass the value of the constructor argument, as long as the type is not ambiguous. In previous cases, all three types are different, so Spring intelligently picks up the right constructor argument, no matter which orders you pass them. Now we are adding one more attribute to the Camera class called flash, as per the following snippet: //Constructor. public Camera(int resolution, String mode, boolean smileShot, boolean flash) { this.resolution = resolution; this.mode = mode; this.smileShot = smileShot; this.flash = flash; } In this case, the constructor arguments smileShot and flash are of the same type (Boolean), and you pass the constructor argument value from XML configuration as per the following snippet: <constructor-arg type="java.lang.String" value="normal"/> <constructor-arg type="boolean" value="true" /> <constructor-arg type="int" value="12" /> <constructor-arg type="boolean" value="false" /> In the preceding scenario, Spring will pick up the following: int value for resolution The string value for mode First Boolean value (true) in sequence for first Boolean argument—smileShot Second Boolean value (false) in sequence for second Boolean argument—flash In short, for similar types in constructor arguments, Spring will pick the first value that comes in the sequence. So sequence does matter in this case. This may lead to logical errors, as you are passing wrong values to the right argument. To avoid such accidental mistakes, Spring provides the facility to define a zero-based index in the <constructor-arg> element, as per the following snippet: <constructor-arg type="java.lang.String" value="normal" index="1"/> <constructor-arg type="boolean" value="true" index="3"/> <constructor-arg type="int" value="12" index="0"/> <constructor-arg type="boolean" value="false" index="2"/> This is more readable and less error-prone. Now Spring will pick up the last value (with index=2) for smileShot, and the second value (with index=3) for flash arguments. Index attributes resolve the ambiguity of two constructor arguments having the same type. If the type you defined in <constructor-arg> is not compatible with the actual type of constructor argument in that index, then Spring will raise an error. So just make sure about this while using index attribute. Implementing Setter-based DI Setter-based DI is generally used for optional dependencies. In case of setter-based DI, the container first creates an instance of your bean, either by calling a no-argument constructor or static factory method. It then passes the said dependencies through each setter method. Dependencies injected through the setter method can be re-injected or changed at a later stage of application. We will understand setter-based DI with the following code base: public class DocumentBase { private DocFinder docFinder; //Setter method to inject dependency. public void setDocFinder(DocFinder docFinder) { this.docFinder = docFinder; } public void performSearch() { this.docFinder.doFind(); } } public class DocFinder { public void doFind() { System.out.println(" Finding in Document Base "); } } public class DIWithSetterCheck { public static void main(String[] args) { ApplicationContext springContext = new ClassPathXmlApplicationContext("application-context.xml"); DocumentBase docBase = (DocumentBase) springContext.getBean("docBase"); docBase.performSearch(); } } The  DocumentBase class depends on DocFinder, and we are passing it through the setter method. You need to define the configuration metadata for Spring, as per the following snippet: <bean id="docBase" class="com.packet.spring.setter.di.DocumentBase"> <property name="docFinder" ref="docFinder" /> </bean> <bean id="docFinder" class="com.packet.spring.setter.di.DocFinder"> </bean> Setter-based DI can be defined through the <property> element under <bean>. The name attribute denotes the name of the setter name. In our case, the name attribute of the property element is docFinder, so Spring will call the setDocFinder method to inject the dependency. The pattern to find the setter method is to prepend set and make the first character capital. The name attribute of the <property> element is case-sensitive. So, if you set the name to docfinder, Spring will try to call the setDocfinder method and will show an error. Just like constructor DI, Setter DI also supports supplying the value for primitives, as per the following snippet: <bean id="docBase" class="com.packet.spring.setter.di.DocumentBase"> <property name="buildNo" value="1.2.6" /> </bean> Since the setter method takes only one argument, there is no scope of argument ambiguity. Whatever value you are passing here, Spring will convert it to an actual primitive type of the setter method parameter. If it's not compatible, it will show an error. We learned to implement DI with Spring and looked at different types of DI like setter-based injection and constructor-based injection. If you found this post useful, be sure to check out the book  'Java 9 Dependency Injection' to learn about factory method in Spring and other concepts in dependency injection. Learning Dependency Injection (DI) Angular 2 Dependency Injection: A powerful design pattern
Read more
  • 0
  • 0
  • 1962
article-image-build-reinforcement-learning-agent-in-keras-tutorial
Amey Varangaonkar
20 Aug 2018
6 min read
Save for later

Build your first Reinforcement learning agent in Keras [Tutorial]

Amey Varangaonkar
20 Aug 2018
6 min read
Today there are a variety of tools available at your disposal to develop and train your own Reinforcement learning agent. In this tutorial, we are going to learn about a Keras-RL agent called CartPole. We will go through this example because it won't consume your GPU, and your cloud budget to run. Also, this logic can be easily extended to other Atari problems. This article is an excerpt taken from the book Deep Learning Quick Reference, written by Mike Bernico. Let's talk quickly about the CartPole environment first: CartPole: The CartPole environment consists of a pole, balanced on a cart. The agent has to learn how to balance the pole vertically, while the cart underneath it moves. The agent is given the position of the cart, the velocity of the cart, the angle of the pole, and the rotational rate of the pole as inputs. The agent can apply a force on either side of the cart. If the pole falls more than 15 degrees from vertical, it's game over for our agent. The CartPole agent will use a fairly modest neural network that you should be able to train fairly quickly even without a GPU. We will start by looking at the model architecture. Then we will define the network's memory, exploration policy, and finally, train the agent. CartPole neural network architecture Three hidden layers with 16 neurons each are more than enough to solve this simple problem. We will use the following code to define the model: def build_model(state_size, num_actions): input = Input(shape=(1,state_size)) x = Flatten()(input) x = Dense(16, activation='relu')(x) x = Dense(16, activation='relu')(x) x = Dense(16, activation='relu')(x) output = Dense(num_actions, activation='linear')(x) model = Model(inputs=input, outputs=output) print(model.summary()) return model The input will be a 1 x state space vector and there will be an output neuron for each possible action that will predict the Q value of that action for each step. By taking the argmax of the outputs, we can choose the action with the highest Q value, but we don't have to do that ourselves as Keras-RL will do it for us. Keras-RL Memory Keras-RL provides us with a class called rl.memory.SequentialMemory that provides a fast and efficient data structure that we can store the agent's experiences in: memory = SequentialMemory(limit=50000, window_length=1) We need to specify a maximum size for this memory object, which is a hyperparameter. As new experiences are added to this memory and it becomes full, old experiences are forgotten. Keras-RL Policy Keras-RL provides an -greedy Q Policy called rl.policy.EpsGreedyQPolicy that we can use to balance exploration and exploitation. We can use rl.policy.LinearAnnealedPolicy to decay our  as the agent steps forward in the world, as shown in the following code: policy = LinearAnnealedPolicy(EpsGreedyQPolicy(), attr='eps', value_max=1., value_min=.1, value_test=.05, nb_steps=10000) Here we're saying that we want to start with a value of 1 for  and go no smaller than 0.1, while testing if our random number is less than 0.05. We set the number of steps between 1 and .1 to 10,000 and Keras-RL handles the decay math for us. Agent With a model, memory, and policy defined, we're now ready to create a deep Q network Agent and send that agent those objects. Keras-RL provides an agent class called rl.agents.dqn.DQNAgent that we can use for this, as shown in the following code: dqn = DQNAgent(model=model, nb_actions=num_actions, memory=memory, nb_steps_warmup=10, target_model_update=1e-2, policy=policy) dqn.compile(Adam(lr=1e-3), metrics=['mae']) Two of these parameters are probably unfamiliar at this point, target_model_update and nb_steps_warmup: nb_steps_warmup: Determines how long we wait before we start doing experience replay, which if you recall, is when we actually start training the network. This lets us build up enough experience to build a proper minibatch. If you choose a value for this parameter that's smaller than your batch size, Keras RL will sample with a replacement. target_model_update: The Q function is recursive and when the agent updates it's network for Q(s,a) that update also impacts the prediction it will make for Q(s', a). This can make for a very unstable network. The way most deep Q network implementations address this limitation is by using a target network, which is a copy of the deep Q network that isn't trained, but rather replaced with a fresh copy every so often. The target_model_update parameter controls how often this happens. Keras-RL Training Keras-RL provides several Keras-like callbacks that allow for convenient model checkpointing and logging. We will use both of those callbacks below. If you would like to see more of the callbacks Keras-RL provides, they can be found here: https://github.com/matthiasplappert/keras-rl/blob/master/rl/callbacks.py. You can also find a Callback class that you can use to create your own Keras-RL callbacks. We will use the following code to train our model: def build_callbacks(env_name): checkpoint_weights_filename = 'dqn_' + env_name + '_weights_{step}.h5f' log_filename = 'dqn_{}_log.json'.format(env_name) callbacks = [ModelIntervalCheckpoint(checkpoint_weights_filename, interval=5000)] callbacks += [FileLogger(log_filename, interval=100)] return callbacks callbacks = build_callbacks(ENV_NAME) dqn.fit(env, nb_steps=50000, visualize=False, verbose=2, callbacks=callbacks) Once the agent's callbacks are built, we can fit the DQNAgent by using a .fit() method. Take note of the visualize parameter in this example. If visualize were set to True, we would be able to watch the agent interact with the environment as we went. However, this significantly slows down the training. Results After the first 250 episodes, we will see that the total rewards for the episode approach 200 and the episode steps also approach 200. This means that the agent has learned to balance the pole on the cart until the environment ends at a maximum of 200 steps. It's of course fun to watch our success, so we can use the DQNAgent .test() method to evaluate for some number of episodes. The following code is used to define this method: dqn.test(env, nb_episodes=5, visualize=True) Here we've set visualize=True so we can watch our agent balance the pole, as shown in the following image: There we go, that's one balanced pole! Alright, I know, I'll admit that balancing a pole on a cart isn't all that cool, but it's a good enough demonstration of the process! Hopefully, you have now understood the dynamics behind the process, and as we discussed earlier, the solution to this problem can be applied to other similar game-based problems. If you found this article to be useful, make sure you check out the book Deep Learning Quick Reference to understand the other different types of reinforcement models you can build using Keras. Top 5 tools for reinforcement learning DeepCube: A new deep reinforcement learning approach solves the Rubik’s cube with no human help OpenAI builds reinforcement learning based system giving robots human like dexterity
Read more
  • 0
  • 0
  • 30199

article-image-app-metrics-analyze-http-traffic-errors-network-performance-net-core-app
Aaron Lazar
20 Aug 2018
12 min read
Save for later

Use App Metrics to analyze HTTP traffic, errors & network performance of a .NET Core app [Tutorial]

Aaron Lazar
20 Aug 2018
12 min read
App Metrics is an open source tool that can be plugged in with the ASP.NET Core applications. It provides real-time insights about how the application is performing and provides a complete overview of the application's health status. It provides metrics in a JSON format and integrates with the Grafana dashboards for visual reporting. App Metrics is based on .NET Standard and runs cross-platform. It provides various extensions and reporting dashboards that can run on Windows and Linux operating system as well. In this article, we will focus on App Metrics, analyse HTTP traffic, errors, and network performance in .NET Core. This tutorial is an extract from the book C# 7 and .NET Core 2.0 High Performance, authored by Ovais Mehboob Ahmed Khan. Setting up App Metrics with ASP.NET Core We can set up App Metrics in the ASP.NET Core application in three easy steps, which are as follows: Install App Metrics. App Metrics can be installed as NuGet packages. Here are the two packages that can be added through NuGet in your .NET Core project: Install-Package App.Metrics Install-Pacakge App.Metrics.AspnetCore.Mvc Add App Metrics in Program.cs. Add UseMetrics to Program.cs in the BuildWebHost method, as follows: public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseMetrics() .UseStartup<Startup>() .Build(); Add App Metrics in Startup.cs. Finally, we can add a metrics resource filter in the ConfigureServices method of the Startup class as follows: public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => options.AddMetricsResourceFilter()); } Run your application. Build and run the application. We can test whether App Metrics is running well by using URLs, as shown in the following table. Just append the URL to the application's root URL: URL Description /metrics Shows metrics using the configured metrics formatter /metrics-text Shows metrics using the configured text formatter /env Shows environment information, which includes the operating system, machine name, assembly name, and version Appending /metrics or /metrics-text to the application's root URL gives complete information about application metrics. /metrics returns the JSON response that can be parsed and represented in a view with some custom parsing. Tracking middleware With App Metrics, we can manually define the typical web metrics which are essential to record telemetry information. However, for ASP.NET Core, there is a tracking middleware that can be used and configured in the project, which contains some built-in key metrics which are specific to the web application. Metrics that are recorded by the Tracking middleware are as follows: Apdex: This is used to monitor the user's satisfaction based on the overall performance of the application. Apdex is an open industry standard that measures the user's satisfaction based on the application's response time. We can configure the threshold of time, T, for each request cycle, and the metrics are calculated based on following conditions: User Satisfaction Description Satisfactory If the response time is less than or equal to the threshold time (T) Tolerating If the response time is between the threshold time (T) and 4 times that of the threshold time (T) in seconds Frustrating If the respo nse time is greater than 4 times that of the threshold time (T) Response times: This provides the overall throughput of the request being processed by the application and the duration it takes per route within the application. Active requests: This provides the list of active requests which have been received on the server in a particular amount of time. Errors: This provides the aggregated results of errors in a percentage that includes the overall error request rate, the overall count of each uncaught exception type, the total number of error requests per HTTP status code, and so on. POST and PUT sizes: This provides the request sizes for HTTP POST and PUT requests. Adding tracking middleware We can add tracking middleware as a NuGet package as follows: Install-Package App.Metrics.AspNetCore.Tracking Tracking middleware provides a set of middleware that is added to record telemetry for the specific metric. We can add the following middleware in the Configure method to measure performance metrics: app.UseMetricsApdexTrackingMiddleware(); app.UseMetricsRequestTrackingMiddleware(); app.UseMetricsErrorTrackingMiddleware(); app.UseMetricsActiveRequestMiddleware(); app.UseMetricsPostAndPutSizeTrackingMiddleware(); app.UseMetricsOAuth2TrackingMiddleware(); Alternatively, we can also use meta-pack middleware, which adds all the available tracking middleware so that we have information about all the different metrics which are in the preceding code: app.UseMetricsAllMiddleware(); Next, we will add tracking middleware in our ConfigureServices method as follows: services.AddMetricsTrackingMiddleware(); In the main Program.cs class, we will modify the BuildWebHost method and add the UseMetricsWebTracking method as follows: public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseMetrics() .UseMetricsWebTracking() .UseStartup<Startup>() .Build(); Setting up configuration Once the middleware is added, we need to set up the default threshold and other configuration values so that reporting can be generated accordingly. The web tracking properties can be configured in the appsettings.json file. Here is the content of the appsettings.json file that contains the MetricWebTrackingOptions JSON key: "MetricsWebTrackingOptions": { "ApdexTrackingEnabled": true, "ApdexTSeconds": 0.1, "IgnoredHttpStatusCodes": [ 404 ], "IgnoredRoutesRegexPatterns": [], "OAuth2TrackingEnabled": true }, ApdexTrackingEnabled is set to true so that the customer satisfaction report will be generated, and ApdexTSeconds is the threshold that decides whether the request response time was satisfactory, tolerating, or frustrating. IgnoredHttpStatusCodes contains the list of status codes that will be ignored if the response returns a 404 status. IgnoredRoutesRegexPatterns are used to ignore specific URIs that match the regular expression, and OAuth2TrackingEnabled can be set to monitor and record the metrics for each client and provide information specific to the request rate, error rate, and POST and PUT sizes for each client. Run the application and do some navigation. Appending /metrics-text in your application URL will display the complete report in textual format. Here is the sample snapshot of what textual metrics looks like: Adding visual reports There are various extensions and reporting plugins available that provide a visual reporting dashboard. Some of them are GrafanaCloud Hosted Metrics, InfluxDB, Prometheus, ElasticSearch, Graphite, HTTP, Console, and Text File. We will configure the InfluxDB extension and see how visual reporting can be achieved. Setting up InfluxDB InfluxDB is the open source time series database developed by Influx Data. It is written in the Go language and is widely used to store time series data for real-time analytics. Grafana is the server that provides reporting dashboards that can be viewed through a browser. InfluxDB can easily be imported as an extension in Grafana to display visual reporting from the InfluxDB database. Setting up the Windows subsystem for Linux In this section, we will set up InfluxDB on the Windows subsystem for the Linux operating system. First of all, we need to enable the Windows subsystem for Linux by executing the following command from the PowerShell as an Administrator: Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux After running the preceding command, restart your computer. Next, we will install Linux distro from the Microsoft store. In our case, we will install Ubuntu from the Microsoft Store. Go to the Microsoft Store, search for Ubuntu, and install it. Once the installation is done, click on Launch: This will open up the console window, which will ask you to create a user account for Linux OS (Operating System). Specify the username and password that will be used. Run the following command to update Ubuntu to the latest stable version from the bash shell. To run bash, open the command prompt, write bash, and hit Enter: Finally, it will ask you to create an Ubuntu username and password. Specify the username and password and hit enter. Installing InfluxDB Here, we will go through some steps to install the InfluxDB database in Ubuntu: To set up InfluxDB, open a command prompt in Administrator mode and run the bash shell. Execute the following commands to the InfluxDB data store on your local PC: $ curl -sL https://repos.influxdata.com/influxdb.key | sudo apt-key add - $ source /etc/lsb-release $ echo "deb https://repos.influxdata.com/${DISTRIB_ID,,} $ {DISTRIB_CODENAME} stable" | sudo tee /etc/apt/sources.list.d/influxdb.list Install InfluxDB by executing the following command: $ sudo apt-get update && sudo apt-get install influxdb Execute the following command to run InfluxDB: $ sudo influxd Start the InfluxDB shell by running the following command: $ sudo influx It will open up the shell where database-specific commands can be executed. Create a database by executing the following command. Specify a meaningful name for the database. In our case, it is appmetricsdb: > create database appmetricsdb Installing Grafana Grafana is an open source tool used to display dashboards in a web interface. There are various dashboards available that can be imported from the Grafana website to display real-time analytics. Grafana can simply be downloaded as a zip file from http://docs.grafana.org/installation/windows/. Once it is downloaded, we can start the Grafana server by clicking on the grafana-server.exe executable from the bin directory. Grafana provides a website that listens on port 3000. If the Grafana server is running, we can access the site by navigating to http://localhost:3000. Adding the InfluxDB dashboard There is an out-of-the-box InfluxDB dashboard available in Grafana which can be imported from the following link: https://grafana.com/dashboards/2125. Copy the dashboard ID and use this to import it into the Grafana website. We can import the InfluxDB dashboard by going to the Manage option on the Grafana website, as follows: From the Manage option, click on the + Dashboard button and hit the New Dashboard option. Clicking on Import Dashboard will lead to Grafana asking you for the dashboard ID: Paste the dashboard ID (for example, 2125) copied earlier into the box and hit Tab. The system will show the dashboard's details, and clicking on the Import button will import it into the system: Configuring InfluxDB We will now configure the InfluxDB dashboard and add a data source that connects to the database that we just created. To proceed, we will go to the Data Sources section on the Grafana website and click on the Add New Datasource option. Here is the configuration that adds the data source for the InfluxDB database: Modifying the Configure and ConfigureServices methods in Startup Up to now, we have set up Ubuntu and the InfluxDB database on our machine. We also set up the InfluxDB data source and added a dashboard through the Grafana website. Next, we will configure our ASP.NET Core web application to push real-time information to the InfluxDB database. Here is the modified ConfigureServices method that initializes the MetricsBuilder to define the attribute related to the application name, environment, and connection details: public void ConfigureServices(IServiceCollection services) { var metrics = new MetricsBuilder() .Configuration.Configure( options => { options.WithGlobalTags((globalTags, info) => { globalTags.Add("app", info.EntryAssemblyName); globalTags.Add("env", "stage"); }); }) .Report.ToInfluxDb( options => { options.InfluxDb.BaseUri = new Uri("http://127.0.0.1:8086"); options.InfluxDb.Database = "appmetricsdb"; options.HttpPolicy.Timeout = TimeSpan.FromSeconds(10); }) .Build(); services.AddMetrics(metrics); services.AddMetricsReportScheduler(); services.AddMetricsTrackingMiddleware(); services.AddMvc(options => options.AddMetricsResourceFilter()); } In the preceding code, we have set the application name app as the assembly name, and the environment env as the stage. http://127.0.0.1:8086 is the URL of the InfluxDB server that listens for the telemetry being pushed by the application. appmetricsdb is the database that we created in the preceding section. Then, we added the AddMetrics middleware and specified the metrics containing the configuration. AddMetricsTrackingMiddleware is used to track the web telemetry information which is displayed on the dashboard, and AddMetricsReportScheduled is used to push the telemetry information to the database. Here is the Configure method that contains UseMetricsAllMiddleware to use App Metrics. UseMetricsAllMiddleware adds all the middleware available in App Metrics: public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseBrowserLink(); app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseMetricsAllMiddleware(); app.UseMvc(); } Rather than calling UseAllMetricsMiddleware, we can also add individual middleware explicitly based on the requirements. Here is the list of middleware that can be added: app.UseMetricsApdexTrackingMiddleware(); app.UseMetricsRequestTrackingMiddleware(); app.UseMetricsErrorTrackingMiddleware(); app.UseMetricsActiveRequestMiddleware(); app.UseMetricsPostAndPutSizeTrackingMiddleware(); app.UseMetricsOAuth2TrackingMiddleware(); Testing the ASP.NET Core App and reporting on the Grafana dashboard To test the ASP.NET Core application and to see visual reporting on the Grafana dashboard, we will go through following steps: Start the Grafana server by going to {installation_directory}\bin\grafana-server.exe. Start bash from the command prompt and run the sudo influx command. Start another bash from the command prompt and run the sudo influx command. Run the ASP.NET Core application. Access http://localhost:3000 and click on the App Metrics dashboard. This will start gathering telemetry information and will display the performance metrics, as shown in the following screenshots: The following graph shows the total throughput in Request Per Minute (RPM), error percentage, and active requests: Here is the Apdex score colorizing the user satisfaction into three different colors, where red is frustrating, orange is tolerating, and green is satisfactory. The following graph shows the blue line being drawn on the green bar, which means that the application performance is satisfactory: The following snapshot shows the throughput graph for all the requests being made, and each request has been colorized with the different colors: red, orange, and green. In this case, there are two HTTP GET requests for the about and contact us pages: Here is the response time graph showing the response time of both requests: If you liked this article and would like to learn more such techniques, go and pick up the full book, C# 7 and .NET Core 2.0 High Performance, authored by Ovais Mehboob Ahmed Khan. Get to know ASP.NET Core Web API [Tutorial] How to call an Azure function from an ASP.NET Core MVC application ASP.NET Core High Performance
Read more
  • 0
  • 0
  • 16529

article-image-best-practices-for-c-code-optimization-tutorial
Aaron Lazar
17 Aug 2018
9 min read
Save for later

Best practices for C# code optimization [Tutorial]

Aaron Lazar
17 Aug 2018
9 min read
There are many factors that negatively impact the performance of a .NET Core application. Sometimes these are minor things that were not considered earlier at the time of writing the code, and are not addressed by the accepted best practices. As a result, to solve these problems, programmers often resort to ad hoc solutions. However, when bad practices are combined together, they produce performance issues. It is always better to know the best practices that help developers write cleaner code and make the application performant. In this article, we will learn the following topics: Boxing and unboxing overhead String concatenation Exceptions handling for versus foreach Delegates This tutorial is an extract from the book, C# 7 and .NET Core 2.0 High Performance, authored by Ovais Mehboob Ahmed Khan. Boxing and unboxing overhead The boxing and unboxing methods are not always good to use and they negatively impact the performance of mission-critical applications. Boxing is a method of converting a value type to an object type, and is done implicitly, whereas unboxing is a method of converting an object type back to a value type and requires explicit casting. Let's go through an example where we have two methods executing a loop of 10 million records, and in each iteration, they are incrementing the counter by 1. The AvoidBoxingUnboxing method is using a primitive integer to initialize and increment it on each iteration, whereas the BoxingUnboxing method is boxing by assigning the numeric value to the object type first and then unboxing it on each iteration to convert it back to the integer type, as shown in the following code: private static void AvoidBoxingUnboxing() { Stopwatch watch = new Stopwatch(); watch.Start(); //Boxing int counter = 0; for (int i = 0; i < 1000000; i++) { //Unboxing counter = i + 1; } watch.Stop(); Console.WriteLine($"Time taken {watch.ElapsedMilliseconds}"); } private static void BoxingUnboxing() { Stopwatch watch = new Stopwatch(); watch.Start(); //Boxing object counter = 0; for (int i = 0; i < 1000000; i++) { //Unboxing counter = (int)i + 1; } watch.Stop(); Console.WriteLine($"Time taken {watch.ElapsedMilliseconds}"); } When we run both methods, we will clearly see the differences in performance. The BoxingUnboxing is executed seven times slower than the AvoidBoxingUnboxing method, as shown in the following screenshot: For mission-critical applications, it's always better to avoid boxing and unboxing. However, in .NET Core, we have many other types that internally use objects and perform boxing and unboxing. Most of the types under System.Collections and System.Collections.Specialized use objects and object arrays for internal storage, and when we store primitive types in these collections, they perform boxing and convert each primitive value to an object type, adding extra overhead and negatively impacting the performance of the application. Other types of System.Data, namely DateSet, DataTable, and DataRow, also use object arrays under the hood. Types under the System.Collections.Generic namespace or typed arrays are the best approaches to use when performance is the primary concern. For example, HashSet<T>, LinkedList<T>, and List<T> are all types of generic collections. For example, here is a program that stores the integer value in ArrayList: private static void AddValuesInArrayList() { Stopwatch watch = new Stopwatch(); watch.Start(); ArrayList arr = new ArrayList(); for (int i = 0; i < 1000000; i++) { arr.Add(i); } watch.Stop(); Console.WriteLine($"Total time taken is {watch.ElapsedMilliseconds}"); } Let's write another program that uses a generic list of the integer type: private static void AddValuesInGenericList() { Stopwatch watch = new Stopwatch(); watch.Start(); List<int> lst = new List<int>(); for (int i = 0; i < 1000000; i++) { lst.Add(i); } watch.Stop(); Console.WriteLine($"Total time taken is {watch.ElapsedMilliseconds}"); } When running both programs, the differences are pretty noticeable. The code with the generic list List<int> is over 10 times faster than the code with ArrayList. The result is as follows: String concatenation In .NET, strings are immutable objects. Two strings refer to the same memory on the heap until the string value is changed. If any of the string is changed, a new string is created on the heap and is allocated a new memory space. Immutable objects are generally thread safe and eliminate the race conditions between multiple threads. Any change in the string value creates and allocates a new object in memory and avoids producing conflicting scenarios with multiple threads. For example, let's initialize the string and assign the Hello World value to the  a string variable: String a = "Hello World"; Now, let's assign the  a string variable to another variable, b: String b = a; Both a and b point to the same value on the heap, as shown in the following diagram: Now, suppose we change the value of b to Hope this helps: b= "Hope this helps"; This will create another object on the heap, where a points to the same and b refers to the new memory space that contains the new text: With each change in the string, the object allocates a new memory space. In some cases, it may be an overkill scenario, where the frequency of string modification is higher and each modification is allocated a separate memory space, creates work for the garbage collector in collecting the unused objects and freeing up space. In such a scenario, it is highly recommended that you use the StringBuilder class. Exception handling Improper handling of exceptions also decreases the performance of an application. The following list contains some of the best practices in dealing with exceptions in .NET Core: Always use a specific exception type or a type that can catch the exception for the code you have written in the method. Using the Exception type for all cases is not a good practice. It is always a good practice to use try, catch, and finally block where the code can throw exceptions. The final block is usually used to clean up the resources, and returns a proper response that the calling code is expecting. In deeply nested code, don't use try catch block and handle it to the calling method or main method. Catching exceptions on multiple stacks slows down performance and is not recommended. Always use exceptions for fatal conditions that terminate the program. Using exceptions for noncritical conditions, such as converting the value to an integer or reading the value from an empty array, is not recommended and should be handled through custom logic. For example, converting a string value to the integer type can be done by using the Int32.Parse method rather than by using the Convert.ToInt32 method and then failing at a point when the string is not represented as a digit. While throwing an exception, add a meaningful message so that the user knows where that exception has actually occurred rather than going through the stack trace. For example, the following code shows a way of throwing an exception and adding a custom message based on the method and class being called: static string GetCountryDetails(Dictionary<string, string> countryDictionary, string key) { try { return countryDictionary[key]; } catch (KeyNotFoundException ex) { KeyNotFoundException argEx = new KeyNotFoundException(" Error occured while executing GetCountryDetails method. Cause: Key not found", ex); throw argEx; } } Throw exceptions rather than returning the custom messages or error codes and handle it in the main calling method. When logging exceptions, always check the inner exception and read the exception message or stack trace. It is helpful, and gives the actual point in the code where the error is thrown. For vs foreach For and foreach are two of the alternative ways of iterating over a list of items. Each of them operates in a different way. The for loop actually loads all the items of the list in memory first and then uses an indexer to iterate over each element, whereas foreach uses an enumerator and iterates until it reaches the end of the list. The following table shows the types of collections that are good to use for for and foreach: Type For/Foreach Typed array Good for both Array list Better with for Generic collections Better with for Delegates Delegates are a type in .NET which hold the reference to the method. The type is equivalent to the function pointer in C or C++. When defining a delegate, we can specify both the parameters that the method can take and its return type. This way, the reference methods will have the same signature. Here is a simple delegate that takes a string and returns an integer: delegate int Log(string n); Now, suppose we have a LogToConsole method that has the same signature as the one shown in the following code. This method takes the string and writes it to the console window: static int LogToConsole(string a) { Console.WriteLine(a); return 1; } We can initialize and use this delegate like this: Log logDelegate = LogToConsole; logDelegate ("This is a simple delegate call"); Suppose we have another method called LogToDatabase that writes the information in the database: static int LogToDatabase(string a) { Console.WriteLine(a); //Log to database return 1; } Here is the initialization of the new logDelegate instance that references the LogToDatabase method: Log logDelegateDatabase = LogToDatabase; logDelegateDatabase ("This is a simple delegate call"); The preceding delegate is the representation of unicast delegates, as each instance refers to a single method. On the other hand, we can also create multicast delegates by assigning  LogToDatabase to the same LogDelegate instance, as follows: Log logDelegate = LogToConsole; logDelegate += LogToDatabase; logDelegate("This is a simple delegate call"); The preceding code seems pretty straightforward and optimized, but under the hood, it has a huge performance overhead. In .NET, delegates are implemented by a MutlicastDelegate class that is optimized to run unicast delegates. It stores the reference of the method to the target property and calls the method directly. For multicast delegates, it uses the invocation list, which is a generic list, and holds the references to each method that is added. With multicast delegates, each target property holds the reference to the generic list that contains the method and executes in sequence. However, this adds an overhead for multicast delegates and takes more time to execute. If you liked this article and would like to learn more such techniques, grab this book, C# 7 and .NET Core 2.0 High Performance, authored by Ovais Mehboob Ahmed Khan. Behavior Scripting in C# and Javascript for game developers Exciting New Features in C# 8.0 Exploring Language Improvements in C# 7.2 and 7.3
Read more
  • 0
  • 1
  • 19855
article-image-rust-for-web-development-tutorial
Aaron Lazar
17 Aug 2018
13 min read
Save for later

Use Rust for web development [Tutorial]

Aaron Lazar
17 Aug 2018
13 min read
You might think that Rust is only meant to be used for complex system development, or that it should be used where security is the number one concern. Thinking of using it for web development might sound to you like huge overkill. We already have proven web-oriented languages that have worked until now, such as PHP or JavaScript, right? This is far from true. Many projects use the web as their platform and for them, it's sometimes more important to be able to receive a lot of traffic without investing in expensive servers rather than using legacy technologies, especially in new products. This is where Rust comes in handy. Thanks to its speed and some really well thought out web-oriented frameworks, Rust performs even better than the legacy web programming languages. In this tutorial, we'll see how Rust can be used for Web Development. This article is an extract from Rust High Performance, authored by Iban Eguia Moraza. Rust is even trying to replace some of the JavaScript on the client side of applications, since Rust can compile to WebAssembly, making it extremely powerful for heavy client-side web workloads. Creating extremely efficient web templates We have seen that Rust is a really efficient language and metaprogramming allows for the creation of even more efficient code. Rust has great templating language support, such as Handlebars and Tera. Rust's Handlebars implementation is much faster than the JavaScript implementation, while Tera is a template engine created for Rust based on Jinja2. In both cases, you define a template file and then you use Rust to parse it. Even though this will be reasonable for most web development, in some cases, it might be slower than pure Rust alternatives. This is where the Maud crate comes in. We will see how it works and how it achieves orders of magnitude faster performance than its counterparts. To use Maud, you will need nightly Rust, since it uses procedural macros. As we saw in previous chapters, if you are using rustup you can simply run rustup override set nightly. Then, you will need to add Maud to your Cargo.toml file in the [dependencies] section: [dependencies] maud = "0.17.2 Maud brings an html!{} procedural macro that enables you to write HTML in Rust. You will, therefore, need to import the necessary crate and macro in your main.rs or lib.rs file, as you will see in the following code. Remember to also add the procedural macro feature at the beginning of the crate: #![feature(proc_macro)] extern crate maud; use maud::html; You will now be able to use the html!{} macro in your main() function. This macro will return a Markup object, which you can then convert to a String or return to Rocket or Iron for your website implementation (you will need to use the relevant Maud features in that case). Let's see what a short template implementation looks like: fn main() { use maud::PreEscaped; let user_name = "FooBar"; let markup = html! { (PreEscaped("<!DOCTYPE html>")) html { head { title { "Test website" } meta charset="UTF-8"; } body { header { nav { ul { li { "Home" } li { "Contact Us" } } } } main { h1 { "Welcome to our test template!" } p { "Hello, " (user_name) "!" } } footer { p { "Copyright © 2017 - someone" } } } } }; println!("{}", markup.into_string()); } It seems like a complex template, but it contains just the basic information a new website should have. We first add a doctype, making sure it will not escape the content (that is what the PreEscaped is for) and then we start the HTML document with two parts: the head and the body. In the head, we add the required title and the charset meta element to tell the browser that we will be using UTF-8. Then, the body contains the three usual sections, even though this can, of course, be modified. One header, one main section, and one footer. I added some example information in each of the sections and showed you how to add a dynamic variable in the main section inside a paragraph. The interesting syntax here is that you can create elements with attributes, such as the meta element, even without content, by finishing it early with a semicolon. You can use any HTML tag and add variables. The generated code will be escaped, except if you ask for non-escaped data, and it will be minified so that it occupies the least space when being transmitted. Inside the parentheses, you can call any function or variable that returns a type that implements the Display trait and you can even add any Rust code if you add braces around it, with the last statement returning a Display element. This works on attributes too. This gets processed at compile time, so that at runtime it will only need to perform the minimum possible amount of work, making it extremely efficient. And not only that; the template will be typesafe thanks to Rust's compile-time guarantees, so you won't forget to close a tag or an attribute. There is a complete guide to the templating engine that can be found at https://maud.lambda.xyz/. Connecting with a database If we want to use SQL/relational databases in Rust, there is no other crate to think about than Diesel. If you need access to NoSQL databases such as Redis or MongoDB, you will also find proper crates, but since the most used databases are relational databases, we will check Diesel here. Diesel makes working with MySQL/MariaDB, PostgreSQL, and SQLite very easy by providing a great ORM and typesafe query builder. It prevents all potential SQL injections at compile time, but is still extremely fast. In fact, it's usually faster than using prepared statements, due to the way it manages connections to databases. Without entering into technical details, we will check how this stable framework works. The development of Diesel has been impressive and it's already working in stable Rust. It even has a stable 1.x version, so let's check how we can map a simple table. Diesel comes with a command-line interface program, which makes it much easier to use. To install it, run cargo install diesel_cli. Note that, by default, this will try to install it for PostgreSQL, MariaDB/MySQL, and SQLite. For this short tutorial, you need to have SQLite 3 development files installed, but if you want to avoid installing all MariaDB/MySQL or PostgreSQL files, you should run the following command: cargo install --no-default-features --features sqlite diesel_cli Then, since we will be using SQLite for our short test, add a file named .env to the current directory, with the following content: DATABASE_URL=test.sqlite We can now run diesel setup and diesel migration generate initial_schema. This will create the test.sqlite SQLite database and a migrations folder, with the first empty initial schema migration. Let's add this to the initial schema up.sql file: CREATE TABLE 'users' ( 'username' TEXT NOT NULL PRIMARY KEY, 'password' TEXT NOT NULL, 'email' TEXT UNIQUE ); In its counterpart down.sql file, we will need to drop the created table: DROP TABLE `users`; Then, we can execute diesel migration run and check that everything went smoothly. We can execute diesel migration redo to check that the rollback and recreation worked properly. We can now start using the ORM. We will need to add diesel, diesel_infer_schema, and dotenv to our Cargo.toml. The dotenv crate will read the .env file to generate the environment variables. If you want to avoid using all the MariaDB/MySQL or PostgreSQL features, you will need to configure diesel for it: [dependencies] dotenv = "0.10.1" [dependencies.diesel] version = "1.1.1" default-features = false features = ["sqlite"] [dependencies.diesel_infer_schema] version = "1.1.0" default-features = false features = ["sqlite"] Let's now create a structure that we will be able to use to retrieve data from the database. We will also need some boilerplate code to make everything work: #[macro_use] extern crate diesel; #[macro_use] extern crate diesel_infer_schema; extern crate dotenv; use diesel::prelude::*; use diesel::sqlite::SqliteConnection; use dotenv::dotenv; use std::env; #[derive(Debug, Queryable)] struct User { username: String, password: String, email: Option<String>, } fn establish_connection() -> SqliteConnection { dotenv().ok(); let database_url = env::var("DATABASE_URL") .expect("DATABASE_URL must be set"); SqliteConnection::establish(&database_url) .expect(&format!("error connecting to {}", database_url)) } mod schema { infer_schema!("dotenv:DATABASE_URL"); } Here, the establish_connection() function will call dotenv() so that the variables in the .env file get to the environment, and then it uses that DATABASE_URL variable to establish the connection with the SQLite database and returns the handle. The schema module will contain the schema of the database. The infer_schema!() macro will get the DATABASE_URL variable and connect to the database at compile time to generate the schema. Make sure you run all the migrations before compiling. We can now develop a small main() function with the basics to list all of the users from the database: fn main() { use schema::users::dsl::*; let connection = establish_connection(); let all_users = users .load::<User>(&connection) .expect("error loading users"); println!("{:?}", all_users); } This will just load all of the users from the database into a list. Notice the use statement at the beginning of the function. This retrieves the required information from the schema for the users table so that we can then call users.load(). As you can see in the guides at diesel.rs, you can also generate Insertable objects, which might not have some of the fields with default values, and you can perform complex queries by filtering the results in the same way you would write a SELECT statement. Creating a complete web server There are multiple web frameworks for Rust. Some of them work in stable Rust, such as Iron and Nickel Frameworks, and some don't, such as Rocket. We will talk about the latter since, even if it forces you to use the latest nightly branch, it's so much more powerful than the rest that it really makes no sense to use any of the others if you have the option to use Rust nightly. Using Diesel with Rocket, apart from the funny wordplay joke, works seamlessly. You will probably be using the two of them together, but in this section, we will learn how to create a small Rocket server without any further complexity. There are some boilerplate code implementations that add a database, cache, OAuth, templating, response compression, JavaScript minification, and SASS minification to the website, such as my Rust web template in GitHub if you need to start developing a real-life Rust web application. Rocket trades that nightly instability, which will break your code more often than not, for simplicity and performance. Developing a Rocket application is really easy and the performance of the results is astonishing. It's even faster than using some other, seemingly simpler frameworks, and of course, it's much faster than most of the frameworks in other languages. So, how does it feel to develop a Rocket application? We start by adding the latest rocket and rocket_codegen crates to our Cargo.toml file and adding a nightly override to our current directory by running rustup override set nightly. The rocket crate contains all the code to run the server, while the rocket_codegen crate is actually a compiler plugin that modifies the language to adapt it for web development. We can now write the default Hello, world! Rocket example: #![feature(plugin)] #![plugin(rocket_codegen)] extern crate rocket; #[get("/")] fn index() -> &'static str { "Hello, world!" } fn main() { rocket::ignite().mount("/", routes![index]).launch(); } In this example, we can see how we ask Rust to let us use plugins to then import the rocket_codegen plugin. This will enable us to use attributes such as #[get] or #[post] with request information that will generate boilerplate code when compiled, leaving our code fairly simple for our development. Also, note that this code has been checked with Rocket 0.3 and it might fail in a future version, since the library is not stable yet. In this case, you can see that the index() function will respond to any GET request with a base URL. This can be modified to accept only certain URLs or to get the path of something from the URL. You can also have overlapping routes with different priorities so that if one is not taken for a request guard, the next will be tried. And, talking about request guards, you can create objects that can be generated when processing a request that will only let the request process a given function if they are properly built. This means that you can, for example, create a User object that will get generated by checking the cookies in the request and comparing them in a Redis database, only allowing the execution of the function for logged-in users. This easily prevents many logic flaws. The main() function ignites the Rocket and mounts the index route at /. This means that you can have multiple routes with the same path mounted at different route paths and they do not need to know about the whole path in the URL. In the end, it will launch the Rocket server and if you run it with cargo run, it will show the following: If you go to the URL, you will see the Hello, World! message. Rocket is highly configurable. It has a rocket_contrib crate which offers templates and further features, and you can create responders to add GZip compression to responses. You can also create your own error responders when an error occurs. You can also configure the behavior of Rocket by using the Rocket.toml file and environment variables. As you can see in this last output, it is running in development mode, which adds some debugging information. You can configure different behaviors for staging and production modes and make them perform faster. Also, make sure that you compile the code in --release mode in production. If you want to develop a web application in Rocket, make sure you check https://rocket.rs/ for further information. Future releases also look promising. Rocket will implement native CSRF and XSS prevention, which, in theory, should prevent all XSS and CSRF attacks at compile time. It will also make further customizations to the engine possible. If you found this article useful and would like to learn more such tips, head over to pick up the book, Rust High Performance, authored by Iban Eguia Moraza. Mozilla is building a bridge between Rust and JavaScript Perform Advanced Programming with Rust Say hello to Sequoia: a new Rust based OpenPGP library to secure your apps
Read more
  • 0
  • 0
  • 13671

article-image-task-parallel-library-multi-threading-net-core
Aaron Lazar
16 Aug 2018
11 min read
Save for later

Task parallel library for easy multi-threading in .NET Core [Tutorial]

Aaron Lazar
16 Aug 2018
11 min read
Compared to the classic threading model in .NET, Task Parallel Library minimizes the complexity of using threads and provides an abstraction through a set of APIs that help developers focus more on the application program instead of focusing on how the threads will be provisioned. In this article, we'll learn how TPL benefits of using traditional threading techniques for concurrency and high performance. There are several benefits of using TPL over threads: It autoscales the concurrency to a multicore level It autoscales LINQ queries to a multicore level It handles the partitioning of the work and uses ThreadPool where required It is easy to use and reduces the complexity of working with threads directly This tutorial is an extract from the book, C# 7 and .NET Core 2.0 High Performance, authored by Ovais Mehboob Ahmed Khan. Creating a task using TPL TPL APIs are available in the System.Threading and System.Threading.Tasks namespaces. They work around the task, which is a program or a block of code that runs asynchronously. An asynchronous task can be run by calling either the Task.Run or TaskFactory.StartNew methods. When we create a task, we provide a named delegate, anonymous method, or a lambda expression that the task executes. Here is a code snippet that uses a lambda expression to execute the ExecuteLongRunningTasksmethod using Task.Run: class Program { static void Main(string[] args) { Task t = Task.Run(()=>ExecuteLongRunningTask(5000)); t.Wait(); } public static void ExecuteLongRunningTask(int millis) { Thread.Sleep(millis); Console.WriteLine("Hello World"); } } In the preceding code snippet, we have executed the ExecuteLongRunningTask method asynchronously using the Task.Run method. The Task.Run method returns the Task object that can be used to further wait for the asynchronous piece of code to be executed completely before the program ends. To wait for the task, we have used the Wait method. Alternatively, we can also use the Task.Factory.StartNew method, which is more advanced and provides more options. While calling the Task.Factory.StartNew method, we can specify CancellationToken, TaskCreationOptions, and TaskScheduler to set the state, specify other options, and schedule tasks. TPL uses multiple cores of the CPU out of the box. When the task is executed using the TPL API, it automatically splits the task into one or more threads and utilizes multiple processors, if they are available. The decision as to how many threads will be created is calculated at runtime by CLR. Whereas a thread only has an affinity to a single processor, running any task on multiple processors needs a proper manual implementation. Task-based asynchronous pattern (TAP) When developing any software, it is always good to implement the best practices while designing its architecture. The task-based asynchronous pattern is one of the recommended patterns that can be used when working with TPL. There are, however, a few things to bear in mind while implementing TAP. Naming convention The method executing asynchronously should have the naming suffix Async. For example, if the method name starts with ExecuteLongRunningOperation, it should have the suffix Async, with the resulting name of ExecuteLongRunningOperationAsync. Return type The method signature should return either a System.Threading.Tasks.Task or System.Threading.Tasks.Task<TResult>. The task's return type is equivalent to the method that returns void, whereas TResult is the data type. Parameters The out and ref parameters are not allowed as parameters in the method signature. If multiple values need to be returned, tuples or a custom data structure can be used. The method should always return Task or Task<TResult>, as discussed previously. Here are a few signatures for both synchronous and asynchronous methods: Synchronous methodAsynchronous methodVoid Execute();Task ExecuteAsync();List<string> GetCountries();Task<List<string>> GetCountriesAsync();Tuple<int, string> GetState(int stateID);Task<Tuple<int, string>> GetStateAsync(int stateID);Person GetPerson(int personID);Task<Person> GetPersonAsync(int personID); Exceptions The asynchronous method should always throw exceptions that are assigned to the returning task. However, the usage errors, such as passing null parameters to the asynchronous method, should be properly handled. Let's suppose we want to generate several documents dynamically based on a predefined templates list, where each template populates the placeholders with dynamic values and writes it on the filesystem. We assume that this operation will take a sufficient amount of time to generate a document for each template. Here is a code snippet showing how the exceptions can be handled: static void Main(string[] args) { List<Template> templates = GetTemplates(); IEnumerable<Task> asyncDocs = from template in templates select GenerateDocumentAsync(template); try { Task.WaitAll(asyncDocs.ToArray()); }catch(Exception ex) { Console.WriteLine(ex); } Console.Read(); } private static async Task<int> GenerateDocumentAsync(Template template) { //To automate long running operation Thread.Sleep(3000); //Throwing exception intentionally throw new Exception(); } In the preceding code, we have a GenerateDocumentAsync method that performs a long running operation, such as reading the template from the database, populating placeholders, and writing a document to the filesystem. To automate this process, we used Thread.Sleep to sleep the thread for three seconds and then throw an exception that will be propagated to the calling method. The Main method loops the templates list and calls the GenerateDocumentAsync method for each template. Each GenerateDocumentAsync method returns a task. When calling an asynchronous method, the exception is actually hidden until the Wait, WaitAll, WhenAll, and other methods are called. In the preceding example, the exception will be thrown once the Task.WaitAll method is called, and will log the exception on the console. Task status The task object provides a TaskStatus that is used to know whether the task is executing the method running, has completed the method, has encountered a fault, or whether some other occurrence has taken place. The task initialized using Task.Run initially has the status of Created, but when the Start method is called, its status is changed to Running. When applying the TAP pattern, all the methods return the Task object, and whether they are using the Task.Run inside, the method body should be activated. That means that the status should be anything other than Created. The TAP pattern ensures the consumer that the task is activated and the starting task is not required. Task cancellation Cancellation is an optional thing for TAP-based asynchronous methods. If the method accepts the CancellationToken as the parameter, it can be used by the caller party to cancel a task. However, for a TAP, the cancellation should be properly handled. Here is a basic example showing how cancellation can be implemented: static void Main(string[] args) { CancellationTokenSource tokenSource = new CancellationTokenSource(); CancellationToken token = tokenSource.Token; Task.Factory.StartNew(() => SaveFileAsync(path, bytes, token)); } static Task<int> SaveFileAsync(string path, byte[] fileBytes, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { Console.WriteLine("Cancellation is requested..."); cancellationToken.ThrowIfCancellationRequested } //Do some file save operation File.WriteAllBytes(path, fileBytes); return Task.FromResult<int>(0); } In the preceding code, we have a SaveFileAsync method that takes the byte array and the CancellationToken as parameters. In the Main method, we initialize the CancellationTokenSource that can be used to cancel the asynchronous operation later in the program. To test the cancellation scenario, we will just call the Cancel method of the tokenSource after the Task.Factory.StartNew method and the operation will be canceled. Moreover, when the task is canceled, its status is set to Cancelled and the IsCompleted property is set to true. Task progress reporting With TPL, we can use the IProgress<T> interface to get real-time progress notifications from the asynchronous operations. This can be used in scenarios where we need to update the user interface or the console app of asynchronous operations. When defining the TAP-based asynchronous methods, defining IProgress<T> in a parameter is optional. We can have overloaded methods that can help consumers to use in the case of specific needs. However, they should only be used if the asynchronous method supports them.  Here is the modified version of SaveFileAsync that updates the user about the real progress: static void Main(string[] args) { var progressHandler = new Progress<string>(value => { Console.WriteLine(value); }); var progress = progressHandler as IProgress<string>; CancellationTokenSource tokenSource = new CancellationTokenSource(); CancellationToken token = tokenSource.Token; Task.Factory.StartNew(() => SaveFileAsync(path, bytes, token, progress)); Console.Read(); } static Task<int> SaveFileAsync(string path, byte[] fileBytes, CancellationToken cancellationToken, IProgress<string> progress) { if (cancellationToken.IsCancellationRequested) { progress.Report("Cancellation is called"); Console.WriteLine("Cancellation is requested..."); } progress.Report("Saving File"); File.WriteAllBytes(path, fileBytes); progress.Report("File Saved"); return Task.FromResult<int>(0); } Implementing TAP using compilers Any method that is attributed with the async keyword (for C#) or Async for (Visual Basic) is called an asynchronous method. The async keyword can be applied to a method, anonymous method, or a Lambda expression, and the language compiler can execute that task asynchronously. Here is a simple implementation of the TAP method using the compiler approach: static void Main(string[] args) { var t = ExecuteLongRunningOperationAsync(100000); Console.WriteLine("Called ExecuteLongRunningOperationAsync method, now waiting for it to complete"); t.Wait(); Console.Read(); } public static async Task<int> ExecuteLongRunningOperationAsync(int millis) { Task t = Task.Factory.StartNew(() => RunLoopAsync(millis)); await t; Console.WriteLine("Executed RunLoopAsync method"); return 0; } public static void RunLoopAsync(int millis) { Console.WriteLine("Inside RunLoopAsync method"); for(int i=0;i< millis; i++) { Debug.WriteLine($"Counter = {i}"); } Console.WriteLine("Exiting RunLoopAsync method"); } In the preceding code, we have the ExecuteLongRunningOperationAsync method, which is implemented as per the compiler approach. It calls the RunLoopAsync that executes a loop for a certain number of milliseconds that is passed in the parameter. The async keyword on the ExecuteLongRunningOperationAsync method actually tells the compiler that this method has to be executed asynchronously, and, once the await statement is reached, the method returns to the Main method that writes the line on a console and waits for the task to be completed. Once the RunLoopAsync is executed, the control comes back to await and starts executing the next statements in the ExecuteLongRunningOperationAsync method. Implementing TAP with greater control over Task As we know, that the TPL is centered on the Task and Task<TResult> objects. We can execute an asynchronous task by calling the Task.Run method and execute a delegate method or a block of code asynchronously and use Wait or other methods on that task. However, this approach is not always adequate, and there are scenarios where we may have different approaches to executing asynchronous operations, and we may use an Event-based Asynchronous Pattern (EAP) or an Asynchronous Programming Model (APM). To implement TAP principles here, and to get the same control over asynchronous operations executing with different models, we can use the TaskCompletionSource<TResult> object. The TaskCompletionSource<TResult> object is used to create a task that executes an asynchronous operation. When the asynchronous operation completes, we can use the TaskCompletionSource<TResult> object to set the result, exception, or state of the task. Here is a basic example that executes the ExecuteTask method that returns Task, where the ExecuteTask method uses the TaskCompletionSource<TResult> object to wrap the response as a Task and executes the ExecuteLongRunningTask through the Task.StartNew method: static void Main(string[] args) { var t = ExecuteTask(); t.Wait(); Console.Read(); } public static Task<int> ExecuteTask() { var tcs = new TaskCompletionSource<int>(); Task<int> t1 = tcs.Task; Task.Factory.StartNew(() => { try { ExecuteLongRunningTask(10000); tcs.SetResult(1); }catch(Exception ex) { tcs.SetException(ex); } }); return tcs.Task; } public static void ExecuteLongRunningTask(int millis) { Thread.Sleep(millis); Console.WriteLine("Executed"); } So now, we've been able to use TPL and TAP over traditional threads, thus improving performance. If you liked this article and would like to learn more such techniques, pick up this book, C# 7 and .NET Core 2.0 High Performance, authored by Ovais Mehboob Ahmed Khan. Get to know ASP.NET Core Web API [Tutorial] .NET Core completes move to the new compiler – RyuJIT Applying Single Responsibility principle from SOLID in .NET Core
Read more
  • 0
  • 0
  • 25494