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
Explore 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

7019 Articles
article-image-mastering-transfer-learning-fine-tuning-bert-and-vision-transformers
Sinan Ozdemir
27 Nov 2024
15 min read
Save for later

Mastering Transfer Learning: Fine-Tuning BERT and Vision Transformers

Sinan Ozdemir
27 Nov 2024
15 min read
This article is an excerpt from the book, "Principles of Data Science", by Sinan Ozdemir. This book provides an end-to-end framework for cultivating critical thinking about data, performing practical data science, building performant machine learning models, and mitigating bias in AI pipelines. Learn the fundamentals of computational math and stats while exploring modern machine learning and large pre-trained models.IntroductionTransfer learning (TL) has revolutionized the field of deep learning by enabling pre-trained models to adapt their broad, generalized knowledge to specific tasks with minimal labeled data. This article delves into TL with BERT and GPT, demonstrating how to fine-tune these advanced models for text classification and image classification tasks. Through hands-on examples, we illustrate how TL leverages pre-trained architectures to simplify complex problems and achieve high accuracy with limited data.TL with BERT and GPTIn this article, we will take some models that have already learned a lot from their pre-training and fine-tune them to perform a new, related task. This process involves adjusting the model’s parameters to better suit the new task, much like fine-tuning a musical instrument:Figure 12.8 – ITLITL takes a pre-trained model that was generally trained on a semi-supervised (or unsupervised) task and then is given labeled data to learn a specific task.Examples of TLLet’s take a look at some examples of TL with specific pre-trained models.Example – Fine-tuning a pre-trained model for text classificationConsider a simple text classification problem. Suppose we need to analyze customer reviews and determine whether they’re positive or negative. We have a dataset of reviews, but it’s not nearly large enough to train a deep learning (DL) model from scratch. We will fine-tune BERT on a text classification task, allowing the model to adapt its existing knowledge to our specific problem.We will have to move away from the popular scikit-learn library to another popular library called transformers, which was created by HuggingFace (the pre-trained model repository I mentioned earlier) as scikit-learn does not (yet) support Transformer models.Figure 12.9 shows how we will have to take the original BERT model and make some minor modifications to it to perform text classification. Luckily, the transformers package has a built-in class to do this for  us called BertForSequenceClassification:Figure 12.9 – Simplest text classification caseIn many TL cases, we need to architect additional layers. In the simplest text classification case, we add a classification layer on top of a pre-trained BERT model so that it can perform the kind of classification we want.The following code block shows an end-to-end code example of fine-tuning BERT on a text classification task. Note that we are also using a package called datasets, also made by HuggingFace, to load a sentiment classification task from IMDb reviews. Let’s  begin by loading up the dataset:# Import necessary libraries from datasets import load_dataset from transformers import BertTokenizer, BertForSequenceClassification, Trainer, TrainingArguments # Load the dataset imdb_data = load_dataset('imdb', split='train[:1000]') # Loading only 1000 samples for a toy example # Define the tokenizer tokenizer = BertTokenizer.from_pretrained('bert-base-uncased') # Preprocess the data def encode(examples): return tokenizer(examples['text'], truncation=True, padding='max_ length', max_length=512) imdb_data = imdb_data.map(encode, batched=True) # Format the dataset to PyTorch tensors imdb_data.set_format(type='torch', columns=['input_ids', 'attention_ mask', 'label'])With our dataset loaded up, we can run some training code to update our BERT model on our labeled data:# Define the model model = BertForSequenceClassification.from_pretrained( 'bert-base-uncased', num_labels=2) # Define the training arguments training_args = TrainingArguments( output_dir='./results', num_train_epochs=1, per_device_train_batch_size=4 ) # Define the trainer trainer = Trainer(model=model, args=training_args, train_dataset=imdb_ data) # Train the model trainer.train() # Save the model model.save_pretrained('./my_bert_model')Once we have our saved model, we can use the following code to run the model against unseen data:from transformers import pipeline # Define the sentiment analysis pipeline nlp = pipeline('sentiment-analysis', model=model, tokenizer=tokenizer) # Use the pipeline to predict the sentiment of a new review review = "The movie was fantastic! I enjoyed every moment of it." result = nlp(review) # Print the result print(f"label: {result[0]['label']}, with score: {round(result[0] ['score'], 4)}") # "The movie was fantastic! I enjoyed every moment of it." # POSITIVE: 99%Example – TL for image classificationWe could take a pre-trained model such as ResNet or the Vision Transformer (shown in Figure 12.10), initially trained on a large-scale image dataset such as ImageNet. This model has already learned to detect various features from images, from simple shapes to complex objects. We can take advantage of this knowledge, fi ne-tuning  the model on a custom image classification task:Figure 12.10 – The Vision TransformerThe Vision Transformer is like a BERT model for images. It relies on many of the same principles, except instead of text tokens, it uses segments of images as “tokens” instead.The following code block shows an end-to-end code example of fine-tuning the Vision Transformer on an image classification task. The code should look very similar to the BERT code from the previous section because the aim of the transformers library is to standardize training and usage of modern pre-trained models so that no matter what task you are performing, they can offer a relatively unified training and inference experience.Let’s begin by loading up our data and taking a look at the kinds of images we have (seen in Figure 12.11). Note that we are only going to use 1% of the dataset to show that you really don’t need that much data to get a lot out of pre-trained models!# Import necessary libraries from datasets import load_dataset from transformers import ViTImageProcessor, ViTForImageClassification from torch.utils.data import DataLoader import matplotlib.pyplot as plt import torch from torchvision.transforms.functional import to_pil_image # Load the CIFAR10 dataset using Hugging Face datasets # Load only the first 1% of the train and test sets train_dataset = load_dataset("cifar10", split="train[:1%]") test_dataset = load_dataset("cifar10", split="test[:1%]") # Define the feature extractor feature_extractor = ViTImageProcessor.from_pretrained('google/vitbase-patch16-224') # Preprocess the data def transform(examples): # print(examples) # Convert to list of PIL Images examples['pixel_values'] = feature_ extractor(images=examples["img"], return_tensors="pt")["pixel_values"] return examples # Apply the transformations train_dataset = train_dataset.map( transform, batched=True, batch_size=32 ).with_format('pt') test_dataset = test_dataset.map( transform, batched=True, batch_size=32 ).with_format('pt')We can similarly use the model using the following code:Figure 12.11 – A single example from CIFAR10 showing an airplaneNow, we can train our pre-trained Vision Transformer:# Define the model model = ViTForImageClassification.from_pretrained( 'google/vit-base-patch16-224', num_labels=10, ignore_mismatched_sizes=True ) LABELS = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck'] model.config.id2label = LABELS # Define a function for computing metrics def compute_metrics(p): predictions, labels = p preds = np.argmax(predictions, axis=1) return {"accuracy": accuracy_score(labels, preds)} # Define the training arguments training_args = TrainingArguments( output_dir='./results', num_train_epochs=5, per_device_train_batch_size=4, load_best_model_at_end=True, # Save and evaluate at the end of each epoch evaluation_strategy='epoch', save_strategy='epoch' ) # Define the trainer trainer = Trainer( model=model, args=training_args, train_dataset=train_dataset, eval_dataset=test_dataset )Our final model has about 95% accuracy on 1% of the test set. We can now use our new classifier on unseen images, as in this next code block:from PIL import Image from transformers import pipeline # Define an image classification pipeline classification_pipeline = pipeline( 'image-classification', model=model, feature_extractor=feature_extractor ) # Load an image image = Image.open('stock_image_plane.jpg') # Use the pipeline to classify the image result = classification_pipeline(image)Figure 12.12 shows the result of this single classification, and it looks like it did pretty well:Figure 12.12 – Our classifier predicting a stock image of a plane correctlyWith minimal labeled data, we can leverage TL to turn models off the shelf into powerhouse predictive models.ConclusionTransfer learning is a transformative technique in deep learning, empowering developers to harness the power of pre-trained models like BERT and the Vision Transformer for specialized tasks. From sentiment analysis to image classification, these models can be fine-tuned with minimal labeled data, offering impressive performance and adaptability. By using libraries like HuggingFace’s transformers, TL streamlines model training, making state-of-the-art AI accessible and versatile across domains. As demonstrated in this article, TL is not only efficient but also a practical way to achieve powerful predictive capabilities with limited resources.Author BioSinan is an active lecturer focusing on large language models and a former lecturer of data science at the Johns Hopkins University. He is the author of multiple textbooks on data science and machine learning including "Quick Start Guide to LLMs". Sinan is currently the founder of LoopGenius which uses AI to help people and businesses boost their sales and was previously the founder of the acquired Kylie.ai, an enterprise-grade conversational AI platform with RPA capabilities. He holds a Master’s Degree in Pure Mathematics from Johns Hopkins University and is based in San Francisco.
Read more
  • 0
  • 0
  • 38736

article-image-google-bypassed-its-own-security-and-privacy-teams-for-project-dragonfly-reveals-intercept
Sugandha Lahoti
30 Nov 2018
5 min read
Save for later

Google bypassed its own security and privacy teams for Project Dragonfly reveals Intercept

Sugandha Lahoti
30 Nov 2018
5 min read
Google’s Project Dragonfly has faced significant criticism and scrutiny from both the public and Google employees. In a major report yesterday, the Intercept revealed how internal conversations around Google’s censored search engine for China shut out Google’s legal, privacy, and security teams. According to named and anonymous senior Googlers who worked on the project and spoke to The Intercept's Ryan Gallagher, Company executives appeared intent on watering down the privacy review. Google bosses also worked to suppress employee criticism of the censored search engine. Project Dragonfly is the secretive search engine that Google is allegedly developing which will comply with the Chinese rules of censorship. It was kept secret from the company at large during the 18 months it was in development until an insider leak led to its existence being revealed in The Intercept. It has been on the receiving end of a constant backlash from various human rights organizations and investigative reporters, since then. Earlier this week, it also faced criticism from human rights organization Amnesty International and was followed by Google employees signing a petition protesting Google’s infamous Project Dragonfly. The secretive way Google operated Dragonfly Majority of the leaks were reported by Yonatan Zunger, a security engineer on the Dragonfly team. He was asked to produce the privacy review for the project in early 2017. However, he faced opposition from Scott Beaumont, Google’s top executive for China and Korea. According to Zunger, Beaumont “wanted the privacy review of Dragonfly]to be pro forma and thought it should defer entirely to his views of what the product ought to be. He did not feel that the security, privacy, and legal teams should be able to question his product decisions, and maintained an openly adversarial relationship with them — quite outside the Google norm.” Beaumont also micromanaged the project and ensured that discussions about Dragonfly and access to documents about it were under his tight control. If some members of the Dragonfly team broke the strict confidentiality rules, then their contracts at Google could be terminated. Privacy report by Zunger In midst of all these conditions, Zunger and his team were still able to produce a privacy report. The report mentioned problematic scenarios that could arise if the search engine was launched in China. The report mentioned that, in China, it would be difficult for Google to legally push back against government requests, refuse to build systems specifically for surveillance, or even notify people of how their data may be used. Zunger’s meetings with the company’s senior leadership on the discussion of the privacy report were repeatedly postponed. Zunger said, “When the meeting did finally take place, in late June 2017, I and my team were not notified, so we missed it and did not attend. This was a deliberate attempt to exclude us.” Dragonfly: Not just an experiment Intercept’s report even demolished Sundar Pichai’s recent public statement on Dragonfly, where he described it as “just an experiment,” adding that it remained unclear whether the company “would or could” eventually launch it in China. Google employees were surprised as they were told to prepare the search engine for launch between January and April 2019, or sooner. “What Pichai said [about Dragonfly being an experiment] was ultimately horse shit,” said one Google source with knowledge of the project. “This was run with 100 percent intention of launch from day one. He was just trying to walk back a delicate political situation.” It is also alleged that Beaumont had intended from day one that the project should only be known about once it had been launched. “He wanted to make sure there would be no opportunity for any internal or external resistance to Dragonfly.” said one Google source to Intercept. This makes us wonder the extent to which Google really is concerned about upholding its founding values, and how far it will go in advocating internet freedom, openness, and democracy. It now looks a lot like a company who simply prioritizes growth and expansion into new markets, even if it means compromising on issues like internet censorship and surveillance. Perhaps we shouldn’t be surprised. Google CEO Sundar Pichai is expected to testify in Congress on Dec. 5 to discuss transparency and bias. Members of Congress will likely also ask about Google's plans in China. Public opinion on Intercept’s report is largely supportive. https://twitter.com/DennGordon/status/1068228199149125634 https://twitter.com/mpjme/status/1068268991238541312 https://twitter.com/cynthiamw/status/1068240969990983680 Google employee and inclusion activist Liz Fong Jones tweeted that she would match $100,000 in pledged donations to a fund to support employees who refuse to work in protest. https://twitter.com/lizthegrey/status/1068212346236096513 She has also shown full support for Zunger https://twitter.com/lizthegrey/status/1068209548320747521 Google employees join hands with Amnesty International urging Google to drop Project Dragonfly OK Google, why are you ok with mut(at)ing your ethos for Project DragonFly? Amnesty International takes on Google over Chinese censored search engine, Project Dragonfly.
Read more
  • 0
  • 0
  • 38721

article-image-mozilla-proposes-webassembly-interface-types-to-enable-language-interoperability
Bhagyashree R
23 Aug 2019
4 min read
Save for later

Mozilla proposes WebAssembly Interface Types to enable language interoperability

Bhagyashree R
23 Aug 2019
4 min read
WebAssembly will soon be able to use the same high-level types in Python, Rust, and Node says Lin Clark, a Principal Research Engineer at Mozilla, with the help of a new proposal: WebAssembly Interface Types. This proposal aims to add a new set of interface types that will describe high-level values like strings, sequences, records, and variants in WebAssembly. https://twitter.com/linclark/status/1164206550010884096 Why WebAssembly Interface Type matters Mozilla and many other companies have been putting their efforts into bringing WebAssembly outside the browser with projects like WASI and Fastly’s Lucet. Developers also want to run WebAssembly from different source languages like Python, Ruby, and Rust. Clark believes there are three reasons why developers want to do that. First, this will allow them to easily use native modules and deliver better speed to their application users. Second, they can use WebAssembly to sandbox native code for better security. Third, they can save time and maintenance cost by sharing native code across platforms. However, currently, this “cross-language integration” is very complicated. The problem is that WebAssembly currently only supports numbers, so it becomes difficult in cases like passing a string between JS and WebAssembly. You will first have to convert the string into an array of numbers and then convert them back into a string. “This means the two languages can call each other’s functions. But if a function takes or returns anything besides numbers, things get complicated,” Clark explains. So, to get past this hurdle you either need to write “a really hard-to-use API that only speaks in numbers” or “add glue code for every single environment you want this module to run in.” This is why Clark and her team have come up with WebAssembly Interface Types. It will allow WebAssembly modules to interoperate with modules running in their own native runtimes and other WebAssembly modules written in different source languages. It will also be able to talk directly with the host systems. It will achieve all of this using rich APIs and complex types. Source: Mozilla WebAssembly Interface Types are different from the types we have in WebAssembly today. Also, there will not be any new operations added to WebAssembly because of them. All the operations will be performed on the concrete types on both communicating sides. Explaining how this will work, Clark wrote, “There’s one key point that makes this possible: with interface types, the two sides aren’t trying to share a representation. Instead, the default is to copy values between one side and the other.” What WebAssembly developers think about this proposal The news sparked a discussion on Hacker News. A user commented that this could in the future prevent a lot of rewrites and duplication, “I'm very happy to see the WebIDL proposal replaced with something generalized.  The article brings up an interesting point: WebAssembly really could enable seamless cross-language integration in the future. Writing a project in Rust, but really want to use that popular face detector written in Python? And maybe the niche language tokenizer written in PHP? And sprinkle ffmpeg on top, without the hassle of target-compatible compilation and worrying about use after free vulnerabilities? No problem use one of the many WASM runtimes popping up and combine all those libraries by using their pre-compiled WASM packages distributed on a package repo like WAPM, with auto-generated bindings that provide a decent API from your host language.” Another user added, ”Of course, cross-language interfaces will always have tradeoffs. But we see Interface Types extending the space where the tradeoffs are worthwhile, especially in combination with wasm's sandboxing.” Some users are also unsure that this will actually work in practice. Here’s what a Reddit user said, “I wonder how well this will work in practice. effectively this is attempting to be universal language interop. that is a bold goal. I suspect this will never work for complicated object graphs. maybe this is for numbers and strings only. I wonder if something like protobuf wouldn't actually be better. it looked from the graphics that memory is still copied anyway (which makes sense, eg going from a cstring to a java string), but this is still marshalling. maybe you can skip this in some cases, but is that important enough to hinge the design there?” To get a deeper understanding of WebAssembly Interface Types, watch this explainer video by Mozilla: https://www.youtube.com/watch?time_continue=17&v=Qn_4F3foB3Q Also, check out Lin Clark’s article, WebAssembly Interface Types: Interoperate with All the Things. Wasmer introduces WebAssembly Interfaces for validating the imports and exports of a Wasm module Fastly CTO Tyler McMullen on Lucet and the future of WebAssembly and Rust [Interview] LLVM WebAssembly backend will soon become Emscripten’s default backend, V8 announces
Read more
  • 0
  • 0
  • 38701

article-image-implementing-autoencoders-using-h2o
Amey Varangaonkar
27 Oct 2017
4 min read
Save for later

Implementing Autoencoders using H2O

Amey Varangaonkar
27 Oct 2017
4 min read
[box type="note" align="" class="" width=""]This excerpt is taken from the book Neural Networks with R, Chapter 7, Use Cases of Neural Networks - Advanced Topics, written by Giuseppe Ciaburro and Balaji Venkateswaran. In this article, we see how R is an effective tool for neural network modelling, by implementing autoencoders using the popular H2O library.[/box] An autoencoder is an ANN used for learning without efficient coding control. The purpose of an autoencoder is to learn coding for a set of data, typically to reduce dimensionality. Architecturally, the simplest form of autoencoder is an advanced and non-recurring neural network very similar to the MLP, with an input level, an output layer, and one or more hidden layers that connect them, but with the layer outputs having the same number of input level nodes for rebuilding their inputs. In this section, we present an example of implementing Autoencoders using H2O on a movie dataset. The dataset used in this example is a set of movies and genre taken from https://grouplens.org/datasets/movielens We use the movies.csv file, which has three columns: movieId title genres There are 164,979 rows of data for clustering. We will use h2o.deeplearning to have the autoencoder parameter fix the clusters. The objective of the exercise is to cluster the movies based on genre, which can then be used to recommend similar movies or same genre movies to the users. The program uses h20.deeplearning, with the autoencoder parameter set to T: library("h2o") setwd ("c://R") #Load the training dataset of movies movies=read.csv ( "movies.csv", header=TRUE) head(movies) model=h2o.deeplearning(2:3, training_frame=as.h2o(movies), hidden=c(2), autoencoder = T, activation="Tanh") summary(model) features=h2o.deepfeatures(model, as.h2o(movies), layer=1) d=as.matrix(features[1:10,]) labels=as.vector(movies[1:10,2]) plot(d,pch=17) text(d,labels,pos=3) Now, let's go through the code: library("h2o") setwd ("c://R") These commands load the library in the R environment and set the working directory where we will have inserted the dataset for the next reading. Then we load the data: movies=read.csv( "movies.csv", header=TRUE) To visualize the type of data contained in the dataset, we analyze a preview of one of these variables: head(movies) The following figure shows the first 20 rows of the movie dataset: Now we build and train model: model=h2o.deeplearning(2:3, training_frame=as.h2o(movies), hidden=c(2), autoencoder = T, activation="Tanh") Let's analyze some of the information contained in model: summary(model) This is an extract from the results of the summary() function: In the next command, we use the h2o.deepfeatures() function to extract the nonlinear feature from an h2o dataset using an H2O deep learning model: features=h2o.deepfeatures(model, as.h2o(movies), layer=1) In the following code, the first six rows of the features extracted from the model are shown: > features DF.L1.C1 DF.L1.C2 1 0.2569208 -0.2837829 2 0.3437048 -0.2670669 3 0.2969089 -0.4235294 4 0.3214868 -0.3093819 5 0.5586608 0.5829145 6 0.2479671 -0.2757966 [9125 rows x 2 columns] Finally, we plot a diagram where we want to see how the model grouped the movies through the results obtained from the analysis: d=as.matrix(features[1:10,]) labels=as.vector(movies[1:10,2]) plot(d,pch=17) text(d,labels,pos=3) The plot of the movies, once clustering is done, is shown next. We have plotted only 100 movie titles due to space issues. We can see some movies being closely placed, meaning they are of the same genre. The titles are clustered based on distances between them, based on genre. Given a large number of titles, the movie names cannot be distinguished, but what appears to be clear is that the model has grouped the movies into three distinct groups. If you found this excerpt useful, make sure you check out the book Neural Networks with R, containing an interesting coverage of many such useful and insightful topics.
Read more
  • 0
  • 1
  • 38655

article-image-lldb-and-command-line
Packt
15 Feb 2017
23 min read
Save for later

LLDB and the Command Line

Packt
15 Feb 2017
23 min read
In this article by Stuart Grimshaw, authors of the book Mastering macOS Programming, we're going to shift up a gear and reach deep into the LLDB environment, both in Xcode and as a standalone process. Some of this stuff may look a little esoteric at first glance, but rest assured, it is anything but. Working professionally as a developer means being comfortable with the command line, being aware of what is available in LLDB, and having at least a working knowledge of the scripting languages that are a part of developing software on almost all platforms. It's also really, really cool. Once you have a bit of momentum behind you, you'll wonder how you ever lived without these tools, which allow you to automate and customize and get right into the inner workings of your code. (For more resources related to this topic, see here.) In this article, you will learn about the following: What LLDB does Running code from within LLDB Creating and manipulating breakpoints and watchpoints How to customize LLDB to your requirements How to run the Swift REPL from within LLDB How to run a Python REPL within LLDB This one will require a lot of hands-on experimentation to familiarize yourself with what is presented here. So, take this one slowly, and try out as much as you can. Once you have absorbed this stuff, you'll never be the same developer again. LLDB So, what is this LLDB? Why do we see it at the console whenever we hit a breakpoint (or a bug)? This is the LLDB prompt: (lldb) Well, LLDB stands for low level debugger, and it does what it says it does. It actually does a bit more than that, which we'll get to very soon. LLDB makes use of several components from the LLVM project, which is basically a compiler, parser, and loads of other stuff that weneed (or Xcode needs) to build a program. However, as interesting as that is to look at, it is out of the scope of this article, and we will focus entirely on the debugger in this article. LLDB is not only available in the debug area console of Xcode, where we have made frequent use of it already,it can also be used at the command line, which we will also cover in this article. The LLDB interface is a very powerful tool; you can print to it from your code, you can interact with it, configure it to your requirements, change settings on the fly, and access both the Swift REPL and the Unix system that underlies Mac OS, without having to terminate a session. Using LLDB Returning to the code, set a breakpoint at this line of code: printObservation() Once execution has stopped at that breakpoint, type the following into the console: (lldb)bt This will produce a list of all the stack frames on the current thread that lead up to the line of code where execution was halted by the breakpoint, bt stands for backtrace. The output will look like this: (lldb) bt * thread #1: tid = 0x105a7d, 0x000000010000177c 5623_16_code`ViewController.testStepCommands(self=0x00006080000c2220) -> () + 12 at ViewController.swift:62, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1 * frame #0: 0x000000010000177c 5623_16_code`ViewController.testStepCommands(self=0x00006080000c2220) -> () + 12 at ViewController.swift:62 frame #1: 0x00000001000014b2 5623_16_code`ViewController.viewDidLoad(self=0x00006080000c2220) -> () + 98 at ViewController.swift:17 ... lots more edited out frame #16: 0x00007fffbfafc255 libdyld.dylib`start + 1 (lldb) There is no need to understand all of this immediately,but looking through it, you will probably recognize the symbols at the top of the stack, since they are the methods that you have coded yourself. Everything leading up to that is provided by the frameworks you use. In this case, we see that most of the work is being done by AppKit, with a modest contribution from our own code (sorry, the truth can hurt at times). Frame0 is the last frame that was put on the stack. Above that, we see some information about the current thread, its number and thread ID (tid) and so on, as well as the line of code at which execution has been halted, and even the reason for doing so. In this case, we have hit breakpoint 3.1. Remember the viewDidLoad symbolic breakpoint produced several breakpoints? That's what the number behind the decimal point means, and breakpoint3 only occurs once, hence there can only be a 3.1. In large projects, this is an excellent way to answer the perennial question, how did the code get here? Debugging line-by-line Once we have halted the program at a breakpoint, we can take over control of its further execution: Continue The following commands are available to continue execution of the code (up until any subsequent breakpoints): (lldb) continue (lldb) c (lldb) thread continue They are all equivalent. Step over The following commands are equivalent to clicking on the step-over button: (lldb) next (lldb) n (lldb) thread step-over Step into The following commands are equivalent to clicking on the step-into button: (lldb) step (lldb) s (lldb) thread step-in This will advance execution of the code by one line, and when used at a function call, it will step into the function. The step-over and step-incommands are only different at a function call, otherwise they behave the same. Step out The following commands are equivalent to clicking on the step-out button: (lldb) finish (lldb) f (lldb) thread step-out Trying it out Spend some time getting used to stepping through the code using these commands. You'll find that very quickly, your muscle memory starts to do most of the work for you, freeing up some mental capacity for actually dealing with whatever bugs you may be dealing with. If you use one of the step-over or step-into commands (n and s are the most convenient), you can hit return again to repeat that command, which is a more comfortable way of repeatedly stepping through a debug session. Enable The following commands are available for enabling and disabling breakpoints: br disable br enable Enabling breakpoints en massedoes not re-enable those that were disabled individually. Printing in LLDB LLDB provides three convenient commands to print details of an object to the console: The p or printcommand gives us a standard description of the object. The pocommand (meaning print object) gives us either a standard description, or a custom description if we have implemented one. The frame variable command prints the same asprint, but does so without executing any code, thus avoiding the danger of side effects. Preparing classes for LLDB description We can provide custom classeswith any description we wish, and have it print with the po command, by declaring the class to conform to the CustomDebugStringConvertibleprotocol, and then implementing its required variable debugDescription. Let's create a Report class, that has a few properties of mixed types, and a debugDescription variable: class Report: CustomDebugStringConvertible { var title: String? var date: Date? var approved: Bool? var debugDescription: String { return "("Report")n(title)n(date)n(approved)" } } Now create an instance of the class, and one by one, populate the optional properties: let report = Report() report.title = "Weekly Summary" report.date = Date() report.approved = true Set a breakpoint at the first of those lines, where the report instance is declared. Now type po into the LLDB console. You'll get <uninitialized> in the console. Type s into the console, to step through the code. Keep your eye on the green tinted position pointer in the breakpoint gutter, as it will show you which lines of code are being executed during the initialization of a Report instance. Type s (or return) another five times until the initialization is complete, and then type po again. At this point we have the report variable initialized, with its properties still set to nil. (lldb) po report <uninitialized> (lldb) s (lldb) s (lldb) s (lldb) s (lldb) s (lldb) po report <uninitialized> (lldb) s (lldb) po report Report nil nil nil Continue stepping through the code, following this session: (lldb) s (lldb) s (lldb) s (lldb) po report Report Optional("Weekly Summary") nil nil etc... As you step through the code, you can see the report variable being populated with data. Stop hooks But what about having an update of an object's state automatically logged to the console everytime the code is stopped? Then we wouldn't need to go through all this typing, and as we continue debugging, we only need to worry about where to set breakpoints. To do that, we can add a so-called one-liner to a breakpoint that is then attached to a stop hook. Run the code again, and this time when the code halts, enter the following into the LLDB console: (lldb) b logReport (lldb) target stop-hook add --one-liner "po report" The first line creates a breakpoint and names it logReport. The second line attaches a command to that breakpoint, equivalent to selecting the debugger commandfrom the Edit Breakpoint... menu as, which does the same as if we had typed po report ourselves. Now add breakpoints to the next three lines of code, so that the code stops at each: Use the continue command (or just c) to move from one breakpoint to the next, and you'll see that, each time, we get a description of the report current state. Later on, we'll see that there is a way to log an object's state every time it changes, without it being dependent on halting the code, and without our having to specify where the changes take place. Printing formattednumbers LLDB contains its own formatting functionality, so when necessary we can format integers before they are printed to the console. We can print the integer asis, using the p command: (lldb) p 111 (Int) $R10 = 111 We can print its binary representation using the p/t command (the t stands for two): (lldb) p/t 111 (Int) $R11 = 0b0000...lots of zeroes...001101111 A hexadecimal representation is also available, using the p/x command: (lldb) p/x 111 (Int) $R12 = 0x000000000000006f An octal representation is available with the p/o command: (lldb) p/o 111 (Int) $R13 = 0157 Executingcode from LLDB One of LLDB's great strengths is its ability to reach into the current state of the program and alter it. So, for example, we could change the title property of our report object while the code is halted on a later breakpoint, with this code: expr report.title = "Monthly Summary" After this, the code runs as if "Monthly Summary" had been entered all along. This is an essential tool to master when debugging; the ability to change values on the fly can save you hundreds of program relaunches in a single day's debugging or prototyping. Type lookups This one is short, but sweet. Using the typelookup command, we get a summary of whatever type we may be interested in. Taking a very small class, our own Report class, as an example, type the following into LLDB: (lldb) type lookup Report This will produce output to the console like the following: class Report : CustomDebugStringConvertible { var title: Swift.String? var date: Foundation.Date? var approved: Swift.Bool? var debugDescription: Swift.String { get {} } @objc deinit init() } Now try it again with a few other types. Try this: (lldb) type lookup Array We won't reproduce the output here (it's quite extensive), but it will give you an idea of just how much information is only an LLDB command away. Breakpoints in LLDB We can add breakpoints of all types, and configure them to our requirements, from within LLDB, and with a little practice you'll find this is a whole lot quicker (as well as being more flexible) than clicking in the breakpoint gutter, right-clicking the breakpoint, and wading through the breakpoint edit window (which rather bizarrely is extremely difficult not to dismiss accidentally). It might take a while before you're convinced of this, but try to remember the time that you quit Macintosh or OS X apps using the menus. Adding a breakpoint To set a breakpoint that is in the current scope, use this command: (lldb) breakpoint set --line 56 This can be abbreviated to: (lldb) b 56 To set a breakpoint somewhere else, add the name of the file after the --file option: (lldb) breakpoint set --file AppDelegate.swift --line 17 You can also set a breakpoint by specifying a method name: (lldb) breakpoint set --method testBreakpoints Imagine setting two dozen breakpoints, across a number of files, some by name, some by line number, and doing it all with the mouse. This console business seriously is faster. Breakpoint list We can inspect a detailed list of all the breakpoints, of whatever type, and whether they are user or project bound breakpoints, with the following command: (lldb) breakpoint list Or its shorter version: (lldb) br li Attaching commands to breakpoints Using the breakpoint list, take note of one of the breakpoints (set an extra one if you have to), which you will alter once you have hit the first breakpoint set in your code. With the program execution halted on that first breakpoint, type the following into the LLDB console (using a breakpoint number from your own breakpoint list): (lldb) breakpoint command add 4.1 You will be prompted to add the command: Enter your debugger command(s). Type 'DONE' to end. > So, do as it says: Enter your debugger command(s). Type 'DONE' to end. >bt > DONE We have chosen bt here, as it's a nice big dump of data onto the console; we won't miss it. Now type: (lldb) c to continue execution, and the program will continue, until it halts at breakpoint 4.1 (or whichever breakpoint you added the command to), and prints the backtrace to the console. Creating a Swift Error breakpoint We saw that we can select Swift Error from the breakpoint types list at the bottom of the breakpoint navigator pane (using the + button), and this can also be done (substantially more quickly) directly in LLDB. (lldb) breakpoint set -E swift Or we can abbreviate this to one of the following: (lldb) br s -E swift (lldb) b -E swift We can also restrict the breakpoint to a specific error type: (lldb) b -E swift -O myError Naming breakpoints You can create de facto groups of breakpoints by naming them. Multiple breakpoints can share a name, and by referring to that name you can enable, disable and delete all those breakpoints with a single command: (lldb) br set -n testStepCommands -N group1 Breakpoint 3: 2 locations. (lldb) br set -n testBreakpoints -N group1 Breakpoint 4: 2 locations. (lldb) breakpoint disable group1 2 breakpoints disabled. Having created two breakpoints that share the name group1, we then disable them by passing the breakpointdisable command the name of the group. Watchpoints We mentioned earlier that we were going to see a way to log any changes tovariables without having to stop the code. This is where we do that. We could, of course, use the variable's setter and getter methods to do this, but the point here is that we don't need to change the program's code and then recompile etc.; all of this can be done without restarting the app. The syntax and console output of watchpoints is generally similar to that of breakpoints, as is made clear from the following input (and console output): (lldb) watchpoint set variable x LLDB confirms watchpoint creation with the details of the watchpoint: Watchpoint created: Watchpoint 1: addr = 0x7fff5fbfec48 size = 8 state = enabled type = w declare @ '/Users/stu/Documents/Books/myBooks/Packt/macOS Programming/Content/ch17 LLDB CLI/5623_17_code/5623_17_code/ViewController.swift:93' watchpoint spec = 'x' When you run code containing a watchpoint, you are basically creating a breakpoint that is attached to a variable rather than a line of code. Adding conditions and commands You can also attach conditions to watchpoint, just as you can to a breakpoint: (lldb) watchpoint modify -c (x==2) And similarly, command add works just as you would expect it to: (lldb) watchpoint command add 1 Enter your debugger command(s). Type 'DONE' to end. >print x > DONE So now you can monitor the progress and state of a variable without disturbing the code at all. In the preceding code, we simply assign a debugger command to watchpoint 1;but how did we get the number of the watchpoint? By checking the watchpoint list. Watchpoint lists Just as for breakpoints, we can get a list of watchpoints, using the following command: (lldb) watchpoint list This gives us a detailed list of all watchpoints, similar to the list below: Number of supported hardware watchpoints: 4 Current watchpoint: Watchpoint 1: addr = 0x7fff5fbfec48 size = 8 state = enabled type = w declare @ '/Users/stu/Documents/Books/myBooks/Packt/macOS Programming/Content/ch17 LLDB CLI/5623_17_code/5623_17_code/ViewController.swift:93' watchpoint spec = 'x' Watchpoints must be small. An Int of Bool is okay, a String object will be too large. Enabling, disabling, and deleting watchpoints The syntax for disabling, enabling and deleting watchpoints is the same as for breakpoints: (lldb) watchpoint disable All watchpoints disabled. (1 watchpoints) This disables watchpoints only, not breakpoints (lldb) watchpoint delete About to delete all watchpoints, do you want to do that?: [Y/n] y All watchpoints removed. (1 watchpoints) Persistent customization If you want LLDB to run commands as it starts up, like defining a list of watchpoints, breakpoints (and a whole ton of other stuff), you can place them in the .lldbinitfile, at these paths: ~.lldbinit-Xcode for LLDB within the Xcode debug console ~/.lldbinit for LLDB in the command line My .initlldb file contains a group of named symbolic breakpoints for things such as viewDidLoad, which are of use in most projects, but which are also disabled by the same file. When I need them for debugging I just need to enable them by name, as opposed to define them from scratch. This is particularly appropriate when breakpoints and watchpoints are a complicated combination of conditions, commands and so on. Getting help in LLBD The following command will provide you with the online docs regarding breakpoints and watchpoints: (lldb) help breakpoint (lldb) help watchpoint Of course, you can access the complete help pages with the following: (lldb) help Try to get accustomed to using the help pages; they contain a lot of information that is otherwise difficult (or tedious) to find, and overcoming any (understandable) reticence to dive into them is better done sooner rather than later. Using shell commands in LLDB You can send shell commands to the system without leaving LLDB by using the platform shell command: (lldb) platform shell pwd /path/to/current/directory... Often, being able to type in these one liners will save you breaking the flow while opening up a Terminal window, navigating to the current directory and so on. Given that shell commands can achieve almost anything on Unix-based machines, you might be tempted to spend a fair amount of time getting used to doing this. Forgot to launch your local server? No problem, just drop into the shell and fire up the server, and then return to the debug session. REPL in LLDB The Swift REPL also runs in LLDB. Actually, whenever you use the Swift REPL, it is running on LLDB: The next time you're running the REPL in a terminal window, try typing a colon, and you'll suddenly discover you were running LLDB all along. To the Swift REPL it from the LLDB console type repl: (lldb) repl 1> Now the REPL prompt is awaiting input. A session might look something like this: (lldb) repl 1>var a = [1,2] a: [Int] = 2 values { [0] = 1 [1] = 2 } 2>a.append(3) 3>a $R0: [Int] = 3 values { [0] = 1 [1] = 2 [2] = 3 } 4> This come is really handy when you need to check an idea in Swift while you are, for example, in the middle of an LLDB session. Switching between LLDB and Swift REPL While in the REPL, you can still punch through to the underlying LLDB session by prepending a command with a colon: 2>:type lookup Report class Report : CustomDebugStringConvertible { var title: Swift.String? var date: Foundation.Date? var approved: Swift.Bool? var debugDescription: Swift.String { get {} } @objc deinit init() } In this example, we’ve printed a summary of our Report class (from a REPL session that knows nothing of that class) by using LLDB's type lookup command preceded by the colon. Leaving a REPL session To leave the REPL and return to LLDB, type just a colon on its own: (lldb) repl 4>print("repl says hi") repl says hi 5>: (lldb) The REPL session has not ended, however. If you re-enter it with the repl command, the variables you defined previously are still in scope. As long as you don't terminate the LLDB session, you can switch between the two as necessary. Using Python in LLDB LLDB has full, built-in Python support. If you type script into the LLDB console, it will open a Python REPL: (lldb) script Python Interactive Interpreter. To exit, type 'quit()', 'exit()'. >>> This is about as powerful a scripting language as you are likely to come across, and now it's just waiting there for you to use it. We'll see an example of what it can do shortly, once we have seen how to reach into the debug session from within the Python REPL. Accessing program variables from Python The Python REPL has a number of tools with which you can reach into your program's session: >>> mynumber = lldb.frame.FindVariable("i") >>> mynumber.GetValue() '42' So, we have the entire Python scripting language at our disposal, with access to the running program's variables. How we could attach Python scripts to a breakpoint; now we can run spontaneous ad hoc Python sessions as well. Pretty amazing stuff! Switching between LLDB and Python REPL Enter quit to leave the Python REPL. However, just as we saw with the Swift REPL, the Python REPL session is not killed as long as the LLDB session is not terminated: (lldb) script Python Interactive Interpreter. To exit, type 'quit()', 'exit()'. >>>a = 1 >>>quit (lldb) script Python Interactive Interpreter. To exit, type 'quit()', 'exit()'. >>>a 1 >>> This ability to switch seamlessly between the two without interrupting either LLDB or the REPL makes this a killer feature of LLDB. One liners from LLDB to Python You can also pass a line of Python to the script command and have it executed without entering the REPL: (lldb) script import os (lldb) script os.system("open http://www.apple.com") Once again, we see an enormous amount of scripting power at our disposal. Getting help in Python There is a pretty huge help document available with the following command from within LLDB: (lldb) script help(lldb) Or use the following command for a smaller, more manageable doc set: (lldb) script help(lldb.process) From these documents you have access to more specific topics about Python in LLDB. It has to be said that these docs are going to be of more use to an experienced Python programmer who is integrating Python into his or her workflow. To learn Python from scratch (and you should, it's easy), you're better off checking out more tutorial-orientated resources. Altogether now You can see that from the debug console, you can run LLDB, shell commands, the Swift REPL, and a Python REPL, all without having to kill the running debug session or fire up the Terminal. Once you get comfortable with making use of this, it becomes an indispensable part of the development process. Standalone LLDB Starting with Xcode 8, LLDB can run in a standalone Terminal session. To launch it, type the lldb command: ~ lldb (lldb) This is great for exploring LLDB, but prototyping and debugging an Xcode project is what we are here for, so let's do that next. Running Xcode projects in a standalone LLDB session To debug an Xcode project, we first need the path of the debug build, which we can get by right-clicking on theProductsfolder in the projectnavigator, and selecting Show in Finder: Now add that path as the argument to the lldb command (dragging the build from the Finder into the Terminal window is a pretty quick way to do that): ~ lldb /Users/.../Build/Products/Debug/5623_17_code.app Hit return. This will produce something similar to the following output: (lldb) target create "/Users/.../Build/Products/Debug/5623_17_code.app" Current executable set to '/Users/.../Build/Products/Debug/5623_17_code.app' (x86_64). We haven't got the code running yet, and we'll set a breakpoint before we do: (lldb) breakpoint set --file ViewController.swift --line 31 Breakpoint 2: where = 5623_17_code`_623_17_code.ViewController.viewDidLoad () -> () + 12 at ViewController.swift:31, address = 0x0000000100001bdc Now run the code: (lldb) run Once we hit that breakpoint, something like the following output will be generated: Process 32522 launched: '/Users/.../Build/Products/Debug/5623_17_code.app/Contents/MacOS/5623_17_code' (x86_64) Process 32522 stopped * thread #1: tid = 0x2039e3, 0x0000000100001bdc 5623_17_code`ViewController.viewDidLoad(self=0x0000000100a69620) -> () + 12 at ViewController.swift:31, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1 frame #0: 0x0000000100001bdc 5623_17_code`ViewController.viewDidLoad(self=0x0000000100a69620) -> () + 12 at ViewController.swift:31 28 29 override func viewDidLoad() 30 { -> 31 super.viewDidLoad() 32 33 let report = Report() 34 report.title = "Weekly Summary" (lldb) As we can see (there's even a little arrow and a code excerpt), the code has been stopped at line 31, as required. Let's print details of the view controller's viewproperty while we're here: (lldb) p self.view (NSView) $R0 = 0x0000000100d18070 { AppKit.NSResponder = { baseNSObject@0 = { isa = NSView } _nextResponder = 0x0000000100d324f0 } } (lldb) Now we can type c to continue the program's execution;but what happens then is that the terminal's input is no longer going to LLDB, which you will notice by the absence of the (lldb) prompt. It is going to the running program. You need to typecontrol + C to get back to LLDB. To return to using the terminal for input to the program, type c to continue. Using these two commands, you can toggle between LLDB and the running process, should you need to. Differences between standalone and Xcode LLDB There are a few important things to note about running standalone LLDB sessions: An LLDB session that is running in a Terminal window ignores all Xcode breakpoints (and other sessions). A command line session is available all of the time, without necessarily having to halt the program's execution. We can have two (or more) open processes at the same time by launching from different terminal sessions (that isTerminal app windows). This means we can try variations in our code at the same time: We can use different variable values We can set different breakpoints and watchpoints Some of these differences make clear the advantages that a standalone session offers over LLDB running in Xcode. We won't necessarily need these features all the time, but it's a good idea to get comfortable with debugging in a separate app. When you do need those features, you'll be glad you did. Summary In this article, we have had more than a superficial glimpse of Xcode and LLDB's advanced features, though there is more to discover. You have learned the following in this article: Using LLDB's advanced debugging features Making your custom classes debug-printable Running your projects in standalone LLDB sessions Using stop hooks and watchpoints in addition to breakpoints Using shell, Swift, and Python commands in an LLDB session in addition to LLDB's own command set Resources for Article:  Further resources on this subject: Maximizing everyday debugging [article] Debugging Applications with PDB and Log Files [article] Debugging mechanisms in Oracle SQL Developer 2.1 using Pl/SQL [article]
Read more
  • 0
  • 1
  • 38639

article-image-why-has-vuejs-become-so-popular
Amit Kothari
19 Jan 2018
5 min read
Save for later

Why has Vue.js become so popular?

Amit Kothari
19 Jan 2018
5 min read
The JavaScript ecosystem is full of choices, with many good web development frameworks and libraries to choose from. One of these frameworks is Vue.js, which is gaining a lot of popularity these days. In this post, we’ll explore why you should use Vue.js, and what makes it an attractive option for your next web project. For the latest Vue.js eBooks and videos, visit our Vue.js page. What is Vue.js? Vue.js is a JavaScript framework for building web interfaces. Vue has been gaining a lot of popularity recently. It ranks number one among the 5 web development tools that will matter in 2018. If you take a look at its GitHub page you can see just how popular it has become – the community has grown at an impressive rate. As a modern web framework, Vue ticks a lot of boxes. It uses a virtual DOM for better performance. A virtual DOM is an abstraction of the real DOM; this means it is lightweight and faster to work with. Vue is also reactive and declarative. This is useful because declarative rendering allows you to create visual elements that update automatically based on the state/data changes. One of the most exciting things about Vue is that it supports the component-based approach of building web applications. Its single file components, which are independent and loosely coupled, allow better reuse and faster development. It’s a tool that can significantly impact how you do things. What are the benefits of using Vue.js? Every modern web framework has strong benefits – if they didn’t, no one would use them after all. But here are some of the reasons why Vue.js is a good web framework that can help you tackle many of today’s development challenges. Check out this post to know more on how to install and use Vue.js for web development Good documentation. One of the things that are important when starting with a new framework is its documentation. Vue.js documentation is very well maintained; it includes a simple but comprehensive guide and well-documented APIs. Learning curve. Another thing to look for when picking a new framework is the learning curve involved. Compared to many other frameworks, Vue's concepts and APIs are much simpler and easier to understand. Also, it is built on top of classic web technologies like JavaScript, HTML, and CSS. This results in a much gentler learning curve. Unlike other frameworks which require further knowledge of different technologies - Angular requires TypeScript for example, and React uses JSX, with Vue we can build a sophisticated app by using HTML-based templates, plain JavaScript, and CSS. Less opinionated, more flexible. Vue is also pretty flexible compared to other popular web frameworks. The core library focuses on the ‘view’ part, using a modular approach that allows you to pick your own solution for other issues. While we can use other libraries for things like state management and routing, Vue offers officially supported companion libraries, which are kept up to date with the core library. This includes Vuex, which is an Elm, Flux, and Redux inspired state management solution, and vue-router, Vue's official routing library, which is powerful and incredibly easy to use with Vue.js. But because Vue is so flexible if you wanted to use Redux instead of Vuex, you can do just that. Vue even supports JSX and TypeScript. And if you like taking a CSS-in-JS approach, many other popular libraries also support Vue. Performance. One of the main reasons many teams are using Vue is because of its performance. Vue is small and even with minimal optimization effort performs better than many other frameworks. This is largely due to its lightweight virtual DOM implementation. Check out the JavaScript frameworks performance benchmark for a useful performance comparison. Tools. Along with a number of companion libraries, Vue also offers really good tools that offer a great development experience. Vue-CLI is Vue’s command line tool. Simple yet powerful, it provides different templates, allows project customization and makes starting a new Vue project incredibly easy. Vue also provides its own dev tools for Chrome (vue-devtools), which allows you to inspect the component tree and Vuex state, view events and even time travel. This makes the debugging process pretty easy. Vue also supports hot reload. Hot reload is great because instead of needing to reload a whole page, it allows you to simply reload only the updated component while maintaining the app's current state. Community. No framework can succeed without community support and, as we’ve seen already, Vue has a very active and constantly growing community. The framework is already adopted by many big companies, and its growth is only going to continue. While it is a great option for web development, Vue is also collaborating with Weex, a platform for building cross-platform mobile apps. Weex is backed by the Alibaba group, which is one of the largest e-commerce businesses in the world. Although Weex is not as mature as other app frameworks like React native, it does allow you to build a UI with Vue, which can be rendered natively on iOS and Android. Vue.js offers plenty of benefits. It performs well and is very easy to learn. However, it is, of course important to pick the right tool for the job, and one framework may work better than the other based on the project requirements and personal preferences. With this in mind, it’s worth comparing Vue.js with other frameworks. Are you considering using Vue.js? Do you already use it? Tell us about your experience! You can get started with building your first Vue.js 2 web application from this post.
Read more
  • 0
  • 3
  • 38626
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 $19.99/month. Cancel anytime
article-image-getting-to-know-tensorflow
Kartikey Pandey
29 Nov 2017
7 min read
Save for later

Getting to know TensorFlow

Kartikey Pandey
29 Nov 2017
7 min read
[box type="note" align="" class="" width=""] The following book excerpt is from the title Machine Learning Algorithms by Guiseppe Bonaccorso. The book describes important Machine Learning algorithms commonly used in the field of data science. These algorithms can be used for supervised as well as unsupervised learning, reinforcement learning, and semi-supervised learning. Few famous ones covered in the book are Linear regression, Logistic Regression, SVM, Naive Bayes, K-Means, Random Forest, TensorFlow, and Feature engineering. [/box] Here, in the article, we look at understanding most important Deep learning library-Tensorflow with contextual examples. Brief Introduction to TensorFlow TensorFlow is a computational framework created by Google and has become one of the most diffused deep-learning toolkits. It can work with both CPUs and GPUs and already implements most of the operations and structures required to build and train a complex model. TensorFlow can be installed as a Python package on Linux, Mac, and Windows (with or without GPU support); however, we suggest you follow the instructions provided on the website to avoid common mistakes. The main concept behind TensorFlow is the computational graph or a set of subsequent operations that transform an input batch into the desired output. In the following figure, there's a schematic representation of a graph: Starting from the bottom, we have two input nodes (a and b), a transpose operation (that works on b), a matrix multiplication and a mean reduction. The init block is a separate operation, which is formally part of the graph, but it's not directly connected to any other node; therefore it's autonomous (indeed, it's a global initializer). As this one is only a brief introduction, it's useful to list all of the most important strategic elements needed to work with TensorFlow so as to be able to build a few simple examples that can show the enormous potential of this framework: Graph: This represents the computational structure that connects a generic input batch with the output tensors through a directed network made of operations. It's defined as a tf.Graph() instance and normally used with a Python context Manager. Placeholder: This is a reference to an external variable, which must be explicitly supplied when it's requested for the output of an operation that uses it directly or indirectly. For example, a placeholder can represent a variable x, which is first transformed into its squared value and then summed to a constant value. The output is thenx2+c, which is materialized by passing a concrete value for x. It's defined as a tf.placeholder() instance. Variable: An internal variable used to store values which are updated by the algorithm. For example, a variable can be a vector containing the weights of a logistic regression. It's normally initialized before a training process and automatically modified by the built-in optimizers. It's defined as a tf.Variable() instance. A variable can also be used to store elements which must not be considered during training processes; in this case, it must be declared with the parameter trainable=False Constant: A constant value defined as a tf.constant() instance. Operation: A mathematical operation that can work with placeholders, variables, and constants. For example, the multiplication of two matrices is an operation defined a tf.constant(). Among all operations, gradient calculation is one of the most important. TensorFlow allows determining the gradients starting from a determined point in the computational graph, until the origin or another point that must be logically before it. We're going to see an example of this Operation. Session: This is a sort of wrapper-interface between TensorFlow and our working environment (for example, Python or C++). When the evaluation of a graph is needed, this macro-operation will be managed by a session, which must be fed with all placeholder values and will produce the required outputs using the requested devices. For our purposes, it's not necessary to go deeper into this concept; however, I invite the reader to retrieve further information from the website or from one of the resources listed at the end of this chapter. It's declared as an instance of tf.Session() or, as we're going to do, an instance of tf.InteractiveSession(). This type of session is particularly useful when working with notebooks or shell commands, because it places itself automatically as the default one. Device: A physical computational device, such as a CPU or a GPU. It's declared explicitly through an instance of the class tf.device()and used with a context manager. When the architecture contains more computational devices, it's possible to split the jobs so as to parallelize many operations. If no device is specified, TensorFlow will use the default one (which is the main CPU or a suitable GPU if all the necessary components are installed). Let’s now analyze this with a simple example here about computing gradients: Computing gradients The option to compute the gradients of all output tensors with respect to any connected input or node is one of the most interesting features of TensorFlow because it allows us to create learning algorithms without worrying about the complexity of all transformations. In this example, we first define a linear dataset representing the function f(x) = x in the range (-100, 100): import numpy as np >>> nb_points = 100 >>> X = np.linspace(-nb_points, nb_points, 200, dtype=np.float32) The corresponding plot is shown in the following figure: Now we want to use TensorFlow to compute: The first step is defining a graph: import tensorflow as tf >>> graph = tf.Graph() Within the context of this graph, we can define our input placeholder and other operations: >>> with graph.as_default(): >>> Xt = tf.placeholder(tf.float32, shape=(None, 1), name='x') >>> Y = tf.pow(Xt, 3.0, name='x_3') >>> Yd = tf.gradients(Y, Xt, name='dx') >>> Yd2 = tf.gradients(Yd, Xt, name='d2x') A placeholder is generally defined with a type (first parameter), a shape, and an optional name. We've decided to use a tf.float32 type because this is the only type also supported by GPUs. Selecting shape=(None, 1) means that it's possible to use any bidimensional vectors with the second dimension equal to 1. The first operation computes the third power if Xt is working on all elements. The second operation computes all the gradients of Y with respect to the input placeholder Xt. The last operation will repeat the gradient computation, but in this case, it uses Yd, which is the output of the first gradient operation. We can now pass some concrete data to see the results. The first thing to do is create a session connected to this graph: >>> session = tf.InteractiveSession(graph=graph) By using this session, we ask any computation using the method run(). All the input parameters must be supplied through a feed-dictionary, where the key is the placeholder, while the value is the actual array: >>> X2, dX, d2X = session.run([Y, Yd, Yd2], feed_dict={Xt: X.reshape((nb_points*2, 1))}) We needed to reshape our array to be compliant with the placeholder. The first argument of run() is a list of tensors that we want to be computed. In this case, we need all operation outputs. The plot of each of them is shown in the following figure: As expected, they represent respectively: x3, 3x2, and 6x. Further in the book, we look at a slightly more complex example of Logistic Regression to implement a logistic regression algorithm. Refer to Chapter 14, Brief Introduction to Deep Learning and Tensorflow of Machine Learning Algorithms to read the complete chapter.    
Read more
  • 0
  • 0
  • 38620

article-image-parallel-programming-patterns
Packt
25 Nov 2013
22 min read
Save for later

Parallel Programming Patterns

Packt
25 Nov 2013
22 min read
(For more resources related to this topic, see here.) Patterns in programming mean a concrete and standard solution to a given problem. Usually, programming patterns are the result of people gathering experience, analyzing the common problems, and providing solutions to these problems. Since parallel programming has existed for quite a long time, there are many different patterns for programming parallel applications. There are even special programming languages to make programming of specific parallel algorithms easier. However, this is where things start to become increasingly complicated. In this article, I will provide a starting point from where you will be able to study parallel programming further. We will review very basic, yet very useful, patterns that are quite helpful for many common situations in parallel programming. First is about using a shared-state object from multiple threads. I would like to emphasize that you should avoid it as much as possible. A shared state is really bad when you write parallel algorithms, but in many occasions it is inevitable. We will find out how to delay an actual computation of an object until it is needed, and how to implement different scenarios to achieve thread safety. The next two recipes will show how to create a structured parallel data flow. We will review a concrete case of a producer/consumer pattern, which is called as Parallel Pipeline. We are going to implement it by just blocking the collection first, and then see how helpful is another library from Microsoft for parallel programming—TPL DataFlow. The last pattern that we will study is the Map/Reduce pattern. In the modern world, this name could mean very different things. Some people consider map/reduce not as a common approach to any problem but as a concrete implementation for large, distributed cluster computations. We will find out the meaning behind the name of this pattern and review some examples of how it might work in case of small parallel applications. Implementing Lazy-evaluated shared states This recipe shows how to program a Lazy-evaluated thread-safe shared state object. Getting ready To start with this recipe, you will need a running Visual Studio 2012. There are no other prerequisites. The source code for this recipe can be found at Packt site. How to do it... For implementing Lazy-evaluated shared states, perform the following steps: Start Visual Studio 2012. Create a new C# Console Application project. In the Program.cs file, add the following using directives: using System; using System.Threading; using System.Threading.Tasks; Add the following code snippet below the Main method: static async Task ProcessAsynchronously() { var unsafeState = new UnsafeState(); Task[] tasks = new Task[4]; for (int i = 0; i < 4; i++) { tasks[i] = Task.Run(() => Worker(unsafeState)); } await Task.WhenAll(tasks); Console.WriteLine(" --------------------------- "); var firstState = new DoubleCheckedLocking(); for (int i = 0; i < 4; i++) { tasks[i] = Task.Run(() => Worker(firstState)); } await Task.WhenAll(tasks); Console.WriteLine(" --------------------------- "); var secondState = new BCLDoubleChecked(); for (int i = 0; i < 4; i++) { tasks[i] = Task.Run(() => Worker(secondState)); } await Task.WhenAll(tasks); Console.WriteLine(" --------------------------- "); var thirdState = new Lazy<ValueToAccess>(Compute); for (int i = 0; i < 4; i++) { tasks[i] = Task.Run(() => Worker(thirdState)); } await Task.WhenAll(tasks); Console.WriteLine(" --------------------------- "); var fourthState = new BCLThreadSafeFactory(); for (int i = 0; i < 4; i++) { tasks[i] = Task.Run(() => Worker(fourthState)); } await Task.WhenAll(tasks); Console.WriteLine(" --------------------------- "); } static void Worker(IHasValue state) { Console.WriteLine("Worker runs on thread id {0}",Thread .CurrentThread.ManagedThreadId); Console.WriteLine("State value: {0}", state.Value.Text); } static void Worker(Lazy<ValueToAccess> state) { Console.WriteLine("Worker runs on thread id {0}",Thread .CurrentThread.ManagedThreadId); Console.WriteLine("State value: {0}", state.Value.Text); } static ValueToAccess Compute() { Console.WriteLine("The value is being constructed on athread id {0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromSeconds(1)); return new ValueToAccess(string.Format("Constructed on thread id {0}", Thread.CurrentThread.ManagedThreadId)); } class ValueToAccess { private readonly string _text; public ValueToAccess(string text) { _text = text; } public string Text { get { return _text; } } } class UnsafeState : IHasValue { private ValueToAccess _value; public ValueToAccess Value { get { if (_value == null) { _value = Compute(); } return _value; } } } class DoubleCheckedLocking : IHasValue { private object _syncRoot = new object(); private volatile ValueToAccess _value; public ValueToAccess Value { get { if (_value == null) { lock (_syncRoot) { if (_value == null) _value = Compute(); } } return _value; } } } class BCLDoubleChecked : IHasValue { private object _syncRoot = new object(); private ValueToAccess _value; private bool _initialized = false; public ValueToAccess Value { get { return LazyInitializer.EnsureInitialized( ref _value, ref _initialized, ref _syncRoot,Compute); } } } class BCLThreadSafeFactory : IHasValue { private ValueToAccess _value; public ValueToAccess Value { get { return LazyInitializer.EnsureInitialized(ref _value,Compute); } } } interface IHasValue { ValueToAccess Value { get; } } Add the following code snippet inside the Main method: var t = ProcessAsynchronously(); t.GetAwaiter().GetResult(); Console.WriteLine("Press ENTER to exit"); Console.ReadLine(); Run the program. How it works... The first example show why it is not safe to use the UnsafeState object with multiple accessing threads. We see that the Construct method was called several times, and different threads use different values, which is obviously not right. To fix this, we can use a lock when reading the value, and if it is not initialized, create it first. It will work, but using a lock with every read operation is not efficient. To avoid using locks every time, there is a traditional approach called the double-checked locking pattern. We check the value for the first time, and if is not null, we avoid unnecessary locking and just use the shared object. However, if it was not constructed yet, we use the lock and then check the value for the second time, because it could be initialized between our first check and the lock operation. If it is still not initialized, only then we compute the value. We can clearly see that this approach works with the second example—there is only one call to the Construct method, and the first-called thread defines the shared object state. Please note that if the lazy- evaluated object implementation is thread-safe, it does not automatically mean that all its properties are thread-safe as well. If you add, for example, an int public property to the ValueToAccess object, it will not be thread-safe; you still have to use interlocked constructs or locking to ensure thread safety. This pattern is very common, and that is why there are several classes in the Base Class Library to help us. First, we can use the LazyInitializer.EnsureInitialized method, which implements the double-checked locking pattern inside. However, the most comfortable option is to use the Lazy<T> class that allows us to have thread-safe Lazy-evaluated, shared state, out of the box. The next two examples show us that they are equivalent to the second one, and the program behaves the same. The only difference is that since LazyInitializer is a static class, we do not have to create a new instance of a class as we do in the case of Lazy<T>, and therefore the performance in the first case will be better in some scenarios. The last option is to avoid locking at all, if we do not care about the Construct method. If it is thread-safe and has no side effects and/or serious performance impacts, we can just run it several times but use only the first constructed value. The last example shows the described behavior, and we can achieve this result by using another LazyInitializer.EnsureInitialized method overload. Implementing Parallel Pipeline with BlockingCollection This recipe will describe how to implement a specific scenario of a producer/consumer pattern, which is called Parallel Pipeline, using the standard BlockingCollection data structure. Getting ready To begin this recipe, you will need a running Visual Studio 2012. There are no other prerequisites. The source code for this recipe can be found at Packt site. How to do it... To understand how to implement Parallel Pipeline using BlockingCollection, perform the following steps: Start Visual Studio 2012. Create a new C# Console Application project. In the Program.cs file, add the following using directives: using System; using System.Collections.Concurrent; using System.Linq; using System.Threading; using System.Threading.Tasks; Add the following code snippet below the Main method: private const int CollectionsNumber = 4; private const int Count = 10; class PipelineWorker<TInput, TOutput> { Func<TInput, TOutput> _processor = null; Action<TInput> _outputProcessor = null; BlockingCollection<TInput>[] _input; CancellationToken _token; public PipelineWorker( BlockingCollection<TInput>[] input, Func<TInput, TOutput> processor, CancellationToken token, string name) { _input = input; Output = new BlockingCollection<TOutput>[_input.Length]; for (int i = 0; i < Output.Length; i++) Output[i] = null == input[i] ? null : new BlockingCollection<TOutput>(Count); _processor = processor; _token = token; Name = name; } public PipelineWorker( BlockingCollection<TInput>[] input, Action<TInput> renderer, CancellationToken token, string name) { _input = input; _outputProcessor = renderer; _token = token; Name = name; Output = null; } public BlockingCollection<TOutput>[] Output { get; private set; } public string Name { get; private set; } public void Run() { Console.WriteLine("{0} is running", this.Name); while (!_input.All(bc => bc.IsCompleted) && !_token.IsCancellationRequested) { TInput receivedItem; int i = BlockingCollection<TInput>.TryTakeFromAny( _input, out receivedItem, 50, _token); if (i >= 0) { if (Output != null) { TOutput outputItem = _processor(receivedItem); BlockingCollection<TOutput>.AddToAny(Output,outputItem); Console.WriteLine("{0} sent {1} to next,on thread id {2}", Name, outputItem,Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromMilliseconds(100)); } else { _outputProcessor(receivedItem); } } else { Thread.Sleep(TimeSpan.FromMilliseconds(50)); } } if (Output != null) { foreach (var bc in Output) bc.CompleteAdding(); } } } Add the following code snippet inside the Main method: var cts = new CancellationTokenSource(); Task.Run(() => { if (Console.ReadKey().KeyChar == 'c') cts.Cancel(); }); var sourceArrays = new BlockingCollection<int>[CollectionsNumber]; for (int i = 0; i < sourceArrays.Length; i++) { sourceArrays[i] = new BlockingCollection<int>(Count); } var filter1 = new PipelineWorker<int, decimal> (sourceArrays, (n) => Convert.ToDecimal(n * 0.97), cts.Token, "filter1" ); var filter2 = new PipelineWorker<decimal, string> (filter1.Output, (s) => String.Format("--{0}--", s), cts.Token, "filter2" ); var filter3 = new PipelineWorker<string, string> (filter2.Output, (s) => Console.WriteLine("The final result is {0} onthread id {1}", s, Thread.CurrentThread.ManagedThreadId), cts.Token,"filter3"); try { Parallel.Invoke( () => { Parallel.For(0, sourceArrays.Length * Count,(j, state) => { if (cts.Token.IsCancellationRequested) { state.Stop(); } int k = BlockingCollection<int>.TryAddToAny(sourceArrays, j); if (k >= 0) { Console.WriteLine("added {0} to source data onthread id {1}", j, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromMilliseconds(100)); } }); foreach (var arr in sourceArrays) { arr.CompleteAdding(); } }, () => filter1.Run(), () => filter2.Run(), () => filter3.Run() ); } catch (AggregateException ae) { foreach (var ex in ae.InnerExceptions) Console.WriteLine(ex.Message + ex.StackTrace); } if (cts.Token.IsCancellationRequested) { Console.WriteLine("Operation has been canceled!Press ENTER to exit."); } else { Console.WriteLine("Press ENTER to exit."); } Console.ReadLine(); Run the program. How it works... In the preceding example, we implement one of the most common parallel programming scenarios. Imagine that we have some data that has to pass through several computation stages, which take a significant amount of time. The latter computation requires the results of the former, so we cannot run them in parallel. If we had only one item to process, there would not be many possibilities to enhance the performance. However, if we run many items through the set of same computation stages, we can use a Parallel Pipeline technique. This means that we do not have to wait until all items pass through the first computation stage to go to the next one. It is enough to have just one item that finishes the stage, we move it to the next stage, and meanwhile the next item is being processed by the previous stage, and so on. As a result, we almost have parallel processing shifted by a time required for the first item to pass through the first computation stage. Here, we use four collections for each processing stage, illustrating that we can process every stage in parallel as well. The first step that we do is to provide a possibility to cancel the whole process by pressing the C key. We create a cancellation token and run a separate task to monitor the C key. Then, we define our pipeline. It consists of three main stages. The first stage is where we put the initial numbers on the first four collections that serve as the item source to the latter pipeline. This code is inside the Parallel.For loop, which in turn is inside the Parallel.Invoke statement, as we run all the stages in parallel; the initial stage runs in parallel as well. The next stage is defining our pipeline elements. The logic is defined inside the PipelineWorker class. We initialize the worker with the input collection, provide a transformation function, and then run the worker in parallel with the other workers. This way we define two workers, or filters, because they filter the initial sequence. One of them turns an integer into a decimal value, and the second one turns a decimal to a string. Finally, the last worker just prints every incoming string to the console. Everywhere we provide a running thread ID to see how everything works. Besides this, we added artificial delays, so the items processing will be more natural, as we really use heavy computations. As a result, we see the exact expected behavior. First, some items are being created on the initial collections. Then, we see that the first filter starts to process them, and as they are being processed, the second filter starts to work, and finally the item goes to the last worker that prints it to the console. Implementing Parallel Pipeline with TPL DataFlow This recipe shows how to implement a Parallel Pipeline pattern with the help of TPL DataFlow library. Getting ready To start with this recipe, you will need a running Visual Studio 2012. There are no other prerequisites. The source code for this recipe could be found at Packt site. How to do it... To understand how to implement Parallel Pipeline with TPL DataFlow, perform the following steps: Start Visual Studio 2012. Create a new C# Console Application project. Add references to the Microsoft TPL DataFlow NuGet package. Right-click on the References folder in the project and select the Manage NuGet Packages... menu option. Now add your preferred references to the Microsoft TPL DataFlow NuGet package. You can use the search option in the Manage NuGet Packages dialog as follows: In the Program.cs file, add the following using directives: using System; using System.Threading; using System.Threading.Tasks; using System.Threading.Tasks.Dataflow; Add the following code snippet below the Main method: async static Task ProcessAsynchronously() { var cts = new CancellationTokenSource(); Task.Run(() => { if (Console.ReadKey().KeyChar == 'c') cts.Cancel(); }); var inputBlock = new BufferBlock<int>( new DataflowBlockOptions { BoundedCapacity = 5, CancellationToken = cts.Token }); var filter1Block = new TransformBlock<int, decimal>( n => { decimal result = Convert.ToDecimal(n * 0.97); Console.WriteLine("Filter 1 sent {0} to the nextstage on thread id {1}", result, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromMilliseconds(100)); return result; }, new ExecutionDataflowBlockOptions {MaxDegreeOfParallelism = 4, CancellationToken =cts.Token }); var filter2Block = new TransformBlock<decimal, string>( n => { string result = string.Format("--{0}--", n); Console.WriteLine("Filter 2 sent {0} to the nextstage on thread id {1}", result, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(TimeSpan.FromMilliseconds(100)); return result; }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 4, CancellationToken =cts.Token }); var outputBlock = new ActionBlock<string>( s => { Console.WriteLine("The final result is {0} on threadid {1}", s, Thread.CurrentThread.ManagedThreadId); }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 4, CancellationToken =cts.Token }); inputBlock.LinkTo(filter1Block, new DataflowLinkOptions {PropagateCompletion = true }); filter1Block.LinkTo(filter2Block, new DataflowLinkOptions { PropagateCompletion = true }); filter2Block.LinkTo(outputBlock, new DataflowLinkOptions { PropagateCompletion = true }); try { Parallel.For(0, 20, new ParallelOptions {MaxDegreeOfParallelism = 4, CancellationToken =cts.Token }, i => { Console.WriteLine("added {0} to source data on threadid {1}", i, Thread.CurrentThread.ManagedThreadId); inputBlock.SendAsync(i).GetAwaiter().GetResult(); }); inputBlock.Complete(); await outputBlock.Completion; Console.WriteLine("Press ENTER to exit."); } catch (OperationCanceledException) { Console.WriteLine("Operation has been canceled!Press ENTER to exit."); } Console.ReadLine(); } Add the following code snippet inside the Main method: var t = ProcessAsynchronously(); t.GetAwaiter().GetResult(); Run the program. How it works... In the previous recipe, we have implemented a Parallel Pipeline pattern to process items through sequential stages. It is quite a common problem, and one of the proposed ways to program such algorithms is using a TPL DataFlow library from Microsoft. It is distributed via NuGet, and is easy to install and use in your application. The TPL DataFlow library contains different type of blocks that can be connected with each other in different ways and form complicated processes that can be partially parallel and sequential where needed. To see some of the available infrastructure, let's implement the previous scenario with the help of the TPL DataFlow library. First, we define the different blocks that will be processing our data. Please note that these blocks have different options that can be specified during their construction; they can be very important. For example, we pass the cancellation token into every block we define, and when we signal the cancellation, all of them will stop working. We start our process with BufferBlock. This block holds items to pass it to the next blocks in the flow. We restrict it to the five-items capacity, specifying the BoundedCapacity option value. This means that when there will be five items in this block, it will stop accepting new items until one of the existing items pass to the next blocks. The next block type is TransformBlock. This block is intended for a data transformation step. Here we define two transformation blocks, one of them creates decimals from integers, and the second one creates a string from a decimal value. There is a MaxDegreeOfParallelism option for this block, specifying the maximum simultaneous worker threads. The last block is the ActionBlock type. This block will run a specified action on every incoming item. We use this block to print our items to the console. Now, we link these blocks together with the help of the LinkTo methods. Here we have an easy sequential data flow, but it is possible to create schemes that are more complicated. Here we also provide DataflowLinkOptions with the PropagateCompletion property set to true. This means that when the step completes, it will automatically propagate its results and exceptions to the next stage. Then we start adding items to the buffer block in parallel, calling the block's Complete method, when we finish adding new items. Then we wait for the last block to complete. In case of a cancellation, we handle OperationCancelledException and cancel the whole process. Implementing Map/Reduce with PLINQ This recipe will describe how to implement the Map/Reduce pattern while using PLINQ. Getting ready To begin with this recipe, you will need a running Visual Studio 2012. There are no other prerequisites. The source code for this recipe can be found at Packt site. How to do it... To understand how to implement Map/Reduce with PLINQ, perform the following steps: Start Visual Studio 2012. Create a new C# Console Application project. In the Program.cs file, add the following using directives: using System; using System.Collections.Generic; using System.IO; using System.Linq; Add the following code snippet below the Main method: private static readonly char[] delimiters =Enumerable.Range(0, 256). Select(i => (char)i).Where(c =>!char.IsLetterOrDigit(c)).ToArray(); private const string textToParse = @" Call me Ishmael. Some years ago - never mind how long precisely - having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen, and regulating the circulation. Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me , that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people's hats off - then, I account it high time to get to sea as soon as I can. ― Herman Melville, Moby Dick. "; Add the following code snippet inside the Main method: var q = textToParse.Split(delimiters) .AsParallel() .MapReduce( s => s.ToLower().ToCharArray() , c => c , g => new[] {new {Char = g.Key, Count = g.Count()}}) .Where(c => char.IsLetterOrDigit(c.Char)) .OrderByDescending( c => c.Count); foreach (var info in q) { Console.WriteLine("Character {0} occured in the text {1}{2}", info.Char, info.Count, info.Count == 1 ? "time" : "times"); } Console.WriteLine(" -------------------------------------------"); const string searchPattern = "en"; var q2 = textToParse.Split(delimiters) .AsParallel() .Where(s => s.Contains(searchPattern)) .MapReduce( s => new [] {s} , s => s , g => new[] {new {Word = g.Key, Count = g.Count()}}) .OrderByDescending(s => s.Count); Console.WriteLine("Words with search pattern '{0}':",searchPattern); foreach (var info in q2) { Console.WriteLine("{0} occured in the text {1} {2}",info.Word, info.Count, info.Count == 1 ? "time" : "times"); } int halfLengthWordIndex = textToParse.IndexOf(' ',textToParse.Length/2); using(var sw = File.CreateText("1.txt")) { sw.Write(textToParse.Substring(0, halfLengthWordIndex)); } using(var sw = File.CreateText("2.txt")) { sw.Write(textToParse.Substring(halfLengthWordIndex)); } string[] paths = new[] { ".\" }; Console.WriteLine(" ------------------------------------------------"); var q3 = paths .SelectMany(p => Directory.EnumerateFiles(p, "*.txt")) .AsParallel() .MapReduce( path => File.ReadLines(path).SelectMany(line =>line.Trim(delimiters).Split (delimiters)),word => string.IsNullOrWhiteSpace(word) ? 't' :word.ToLower()[0], g => new [] { new {FirstLetter = g.Key, Count = g.Count()}}) .Where(s => char.IsLetterOrDigit(s.FirstLetter)) .OrderByDescending(s => s.Count); Console.WriteLine("Words from text files"); foreach (var info in q3) { Console.WriteLine("Words starting with letter '{0}'occured in the text {1} {2}", info.FirstLetter,info.Count, info.Count == 1 ? "time" : "times"); } Add the following code snippet after the Program class definition: static class PLINQExtensions { public static ParallelQuery<TResult> MapReduce<TSource,TMapped, TKey, TResult>( this ParallelQuery<TSource> source, Func<TSource, IEnumerable<TMapped>> map, Func<TMapped, TKey> keySelector, Func<IGrouping<TKey, TMapped>, IEnumerable<TResult>> reduce) { return source.SelectMany(map) .GroupBy(keySelector) .SelectMany(reduce); } } Run the program. How it works... The Map/Reduce functions are another important parallel programming pattern. It is suitable for a small program and large multi-server computations. The meaning of this pattern is that you have two special functions to apply to your data. The first of them is the Map function. It takes a set of initial data in a key/value list form and produces another key/value sequence, transforming the data to the comfortable format for further processing. Then we use another function called Reduce. The Reduce function takes the result of the Map function and transforms it to a smallest possible set of data that we actually need. To understand how this algorithm works, let's look through the recipe. First, we define a relatively large text in the string variable: textToParse. We need this text to run our queries on. Then we define our Map/Reduce implementation as a PLINQ extension method in the PLINQExtensions class. We use SelectMany to transform the initial sequence to the sequence we need by applying the Map function. This function produces several new elements from one sequence element. Then we choose how we group the new sequence with the keySelector function, and we use GroupBy with this key to produce an intermediate key/value sequence. The last thing we do is applying Reduce to the resulting grouped sequence to get the result. In our first example, we split the text into separate words, and then we chop each word into character sequences with the help of the Map function, and group the result by the character value. The Reduce function finally transforms the sequence into a key value pair, where we have a character and a number for the times it was used in the text ordered by the usage. Therefore, we are able to count each character appearance in the text in parallel (since we use PLINQ to query the initial data). The next example is quite similar, but now we use PLINQ to filter the sequence leaving only the words containing our search pattern, and we then get all those words sorted by their usage in the text. Finally, the last example uses file I/O. We save the sample text on the disk, splitting it into two files. Then we define the Map function as producing a number of strings from the directory name, which are all the words from all the lines in all text files in the initial directory. Then we group those words by the first letter (filtering out the empty strings) and use reduce to see which letter is most often used as the first word letter in the text. What is nice is that we can easily change this program to be distributed by just using other implementations of map and reduce functions, and we still are able to use PLINQ with them to make our program easy to read and maintain. Summary In this article we covered implementing lazy-evaluated shared states, implementing Parallel Pipeline using BlockingCollection and TPL DataFlow, and finally we covered the implementation of Map/Reduce with PLINQ. Resources for Article: Further resources on this subject: Simplifying Parallelism Complexity in C# [Article] Watching Multiple Threads in C# [Article] Low-level C# Practices [Article]
Read more
  • 0
  • 0
  • 38467

article-image-using-handlebars-express
Packt
10 Aug 2015
17 min read
Save for later

Using Handlebars with Express

Packt
10 Aug 2015
17 min read
In this article written by Paul Wellens, author of the book Practical Web Development, we cover a brief description about the following topics: Templates Node.js Express 4 Templates Templates come in many shapes or forms. Traditionally, they are non-executable files with some pre-formatted text, used as the basis of a bazillion documents that can be generated with a computer program. I worked on a project where I had to write a program that would take a Microsoft Word template, containing parameters like $first, $name, $phone, and so on, and generate a specific Word document for every student in a school. Web templating does something very similar. It uses a templating processor that takes data from a source of information, typically a database and a template, a generic HTML file with some kind of parameters inside. The processor then merges the data and template to generate a bunch of static web pages or dynamically generates HTML on the fly. If you have been using PHP to create dynamic webpages, you will have been busy with web templating. Why? Because you have been inserting PHP code inside HTML files in between the <?php and ?> strings. Your templating processor was the Apache web server that has many additional roles. By the time your browser gets to see the result of your code, it is pure HTML. This makes this an example of server side templating. You could also use Ajax and PHP to transfer data in the JSON format and then have the browser process that data using JavaScript to create the HTML you need. Combine this with using templates and you will have client side templating. Node.js What Le Sacre du Printemps by Stravinsky did to the world of classical music, Node.js may have done to the world of web development. At its introduction, it shocked the world. By now, Node.js is considered by many as the coolest thing. Just like Le Sacre is a totally different kind of music—but by now every child who has seen Fantasia has heard it—Node.js is a different way of doing web development. Rather than writing an application and using a web server to soup up your code to a browser, the application and the web server are one and the same. This may sound scary, but you should not worry as there is an entire community that developed modules you can obtain using the npm tool. Before showing you an example, I need to point out an extremely important feature of Node.js: the language in which you will write your web server and application is JavaScript. So Node.js gives you server side JavaScript. Installing Node.js How to install Node.js will be different, depending on your OS, but the result is the same everywhere. It gives you two programs: Node and npm. npm The node packaging manager (npm)is the tool that you use to look for and install modules. Each time you write code that needs a module, you will have to add a line like this in: var module = require('module'); The module will have to be installed first, or the code will fail. This is how it is done: npm install module or npm -g install module The latter will attempt to install the module globally, the former, in the directory where the command is issued. It will typically install the module in a folder called node_modules. node The node program is the command to use to start your Node.js program, for example: node myprogram.js node will start and interpret your code. Type Ctrl-C to stop node. Now create a file myprogram.js containing the following text: var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello Worldn'); }).listen(8080, 'localhost'); console.log('Server running at http://localhost:8080'); So, if you installed Node.js and the required http module, typing node myprogram.js in a terminal window, your console will start up a web server. And, when you type http://localhost:8080 in a browser, you will see the world famous two word program example on your screen. This is the equivalent of getting the It works! thing, after testing your Apache web server installation. As a matter of fact, if you go to http://localhost:8080/it/does/not/matterwhat, the same will appear. Not very useful maybe, but it is a web server. Serving up static content This does not work in a way we are used to. URLs typically point to a file (or a folder, in which case the server looks for an index.html file) , foo.html, or bar.php, and when present, it is served up to the client. So what if we want to do this with Node.js? We will need a module. Several exist to do the job. We will use node-static in our example. But first we need to install it: npm install node-static In our app, we will now create not only a web server, but a fileserver as well. It will serve all the files in the local directory public. It is good to have all the so called static content together in a separate folder. These are basically all the files that will be served up to and interpreted by the client. As we will now end up with a mix of client code and server code, it is a good practice to separate them. When you use the Express framework, you have an option to have Express create these things for you. So, here is a second, more complete, Node.js example, including all its static content. hello.js, our node.js app var http = require('http'); var static = require('node-static'); var fileServer = new static.Server('./public'); http.createServer(function (req, res) { fileServer.serve(req,res); }).listen(8080, 'localhost'); console.log('Server running at http://localhost:8080'); hello.html is stored in ./public. <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Hello world document</title> <link href="./styles/hello.css" rel="stylesheet"> </head> <body> <h1>Hello, World</h1> </body> </html> hello.css is stored in public/styles. body { background-color:#FFDEAD; } h1 { color:teal; margin-left:30px; } .bigbutton { height:40px; color: white; background-color:teal; margin-left:150px; margin-top:50px; padding:15 15 25 15; font-size:18px; } So, if we now visit http://localhost:8080/hello, we will see our, by now too familiar, Hello World message with some basic styling, proving that our file server also delivered the CSS file. You can easily take it one step further and add JavaScript and the jQuery library and put it in, for example, public/js/hello.js and public/js/jquery.js respectively. Too many notes With Node.js, you only install the modules that you need, so it does not include the kitchen sink by default! You will benefit from that for as far as performance goes. Back in California, I have been a proud product manager of a PC UNIX product, and one of our coolest value-add was a tool, called kconfig, that would allow people to customize what would be inside the UNIX kernel, so that it would only contain what was needed. This is what Node.js reminds me of. And it is written in C, as was UNIX. Deja vu. However, if we wanted our Node.js web server to do everything the Apache Web Server does, we would need a lot of modules. Our application code needs to be added to that as well. That means a lot of modules. Like the critics in the movie Amadeus said: Too many notes. Express 4 A good way to get the job done with fewer notes is by using the Express framework. On the expressjs.com website, it is called a minimal and flexible Node.js web application framework, providing a robust set of features for building web applications. This is a good way to describe what Express can do for you. It is minimal, so there is little overhead for the framework itself. It is flexible, so you can add just what you need. It gives a robust set of features, which means you do not have to create them yourselves, and they have been tested by an ever growing community. But we need to get back to templating, so all we are going to do here is explain how to get Express, and give one example. Installing Express As Express is also a node module, we install it as such. In your project directory for your application, type: npm install express You will notice that a folder called express has been created inside node_modules, and inside that one, there is another collection of node-modules. These are examples of what is called middleware. In the code example that follows, we assume app.js as the name of our JavaScript file, and app for the variable that you will use in that file for your instance of Express. This is for the sake of brevity. It would be better to use a string that matches your project name. We will now use Express to rewrite the hello.js example. All static resources in the public directory can remain untouched. The only change is in the node app itself: var express = require('express'); var path = require('path'); var app = express(); app.set('port', process.env.PORT || 3000); var options = { dotfiles: 'ignore', extensions: ['htm', 'html'], index: false }; app.use(express.static(path.join(__dirname, 'public') , options )); app.listen(app.get('port'), function () { console.log('Hello express started on http://localhost:' + app.get('port') + '; press Ctrl-C to terminate.' ); }); This code uses so called middleware (static) that is included with express. There is a lot more available from third parties. Well, compared to our node.js example, it is about the same number of lines. But it looks a lot cleaner and it does more for us. You no longer need to explicitly include the HTTP module and other such things. Templating and Express We need to get back to templating now. Imagine all the JavaScript ecosystem we just described. Yes, we could still put our client JavaScript code in between the <script> tags but what about the server JavaScript code? There is no such thing as <?javascript ?> ! Node.js and Express, support several templating languages that allow you to separate layout and content, and which have the template system do the work of fetching the content and injecting it into the HTML. The default templating processor for Express appears to be Jade, which uses its own, albeit more compact than HTML, language. Unfortunately, that would mean that you have to learn yet another syntax to produce something. We propose to use handlebars.js. There are two reasons why we have chosen handlebars.js: It uses <html> as the language It is available on both the client and server side Getting the handlebars module for Express Several Express modules exist for handlebars. We happen to like the one with the surprising name express-handlebars. So, we install it, as follows: npm install express-handlebars Layouts I almost called this section templating without templates as our first example will not use a parameter inside the templates. Most websites will consist of several pages, either static or dynamically generated ones. All these pages usually have common parts; a header and footer part, a navigation part or menu, and so on. This is the layout of our site. What distinguishes one page from another, usually, is some part in the body of the page where the home page has different information than the other pages. With express-handlebars, you can separate layout and content. We will start with a very simple example. Inside your project folder that contains public, create a folder, views, with a subdirectory layout. Inside the layouts subfolder, create a file called main.handlebars. This is your default layout. Building on top of the previous example, have it say: <!doctype html> <html> <head> <title>Handlebars demo</title> </head> <link href="./styles/hello.css" rel="stylesheet"> <body> {{{body}}} </body> </html> Notice the {{{body}}} part. This token will be replaced by HTML. Handlebars escapes HTML. If we want our HTML to stay intact, we use {{{ }}}, instead of {{ }}. Body is a reserved word for handlebars. Create, in the folder views, a file called hello.handlebars with the following content. This will be one (of many) example of the HTML {{{body}}}, which will be replaced by: <h1>Hello, World</h1> Let’s create a few more june.handlebars with: <h1>Hello, June Lake</h1> And bodie.handlebars containing: <h1>Hello, Bodie</h1> Our first handlebars example Now, create a file, handlehello.js, in the project folder. For convenience, we will keep the relevant code of the previous Express example: var express = require('express'); var path = require('path'); var app = express(); var exphbs = require(‘express-handlebars’); app.engine('handlebars', exphbs({defaultLayout: 'main'})); app.set('view engine', 'handlebars'); app.set('port', process.env.PORT || 3000); var options = { dotfiles: 'ignore', etag: false, extensions: ['htm', 'html'], index: false }; app.use(express.static(path.join(__dirname, 'public') , options  )); app.get('/', function(req, res) { res.render('hello');   // this is the important part }); app.get('/bodie', function(req, res) { res.render('bodie'); }); app.get('/june', function(req, res) { res.render('june'); }); app.listen(app.get('port'),  function () { console.log('Hello express started on http://localhost:' + app.get('port') + '; press Ctrl-C to terminate.' ); }); Everything that worked before still works, but if you type http://localhost:3000/, you will see a page with the layout from main.handlebars and {{{body}}} replaced by, you guessed it, the same Hello World with basic markup that looks the same as our hello.html example. Let’s look at the new code. First, of course, we need to add a require statement for our express-handlebars module, giving us an instance of express-handlebars. The next two lines specify what the view engine is for this app and what the extension is that is used for the templates and layouts. We pass one option to express-handlebars, defaultLayout, setting the default layout to be main. This way, we could have different versions of our app with different layouts, for example, one using Bootstrap and another using Foundation. The res.render calls determine which views need to be rendered, so if you type http:// localhost:3000/june, you will get Hello, June Lake, rather than Hello World. But this is not at all useful, as in this implementation, you still have a separate file for each Hello flavor. Let’s create a true template instead. Templates In the views folder, create a file, town.handlebars, with the following content: {{!-- Our first template with tokens --}} <h1>Hello, {{town}} </h1> Please note the comment line. This is the syntax for a handlebars comment. You could HTML comments as well, of course, but the advantage of using handlebars comments is that it will not show up in the final output. Next, add this to your JavaScript file: app.get('/lee', function(req, res) { res.render('town', { town: "Lee Vining"}); }); Now, we have a template that we can use over and over again with different context, in this example, a different town name. All you have to do is pass a different second argument to the res.render call, and {{town}} in the template, will be replaced by the value of town in the object. In general, what is passed as the second argument is referred to as the context. Helpers The token can also be replaced by the output of a function. After all, this is JavaScript. In the context of handlebars, we call those helpers. You can write your own, or use some of the cool built-in ones, such as #if and #each. #if/else Let us update town.handlebars as follows: {{#if town}} <h1>Hello, {{town}} </h1> {{else}} <h1>Hello, World </h1> {{/if}} This should be self explanatory. If the variable town has a value, use it, if not, then show the world. Note that what comes after #if can only be something that is either true of false, zero or not. The helper does not support a construct such as #if x < y. #each A very useful built-in helper is #each, which allows you to walk through an array of things and generate HTML accordingly. This is an example of the code that could be inside your app and the template you could use in your view folder: app.js code snippet var californiapeople = {    people: [ {“name":"Adams","first":"Ansel","profession":"photographer",    "born"       :"SanFrancisco"}, {“name":"Muir","first":"John","profession":"naturalist",    "born":"Scotland"}, {“name":"Schwarzenegger","first":"Arnold",    "profession":"governator","born":"Germany"}, {“name":"Wellens","first":"Paul","profession":"author",    "born":"Belgium"} ]   }; app.get('/californiapeople', function(req, res) { res.render('californiapeople', californiapeople); }); template (californiapeople.handlebars) <table class=“cooltable”> {{#each people}}    <tr><td>{{first}}</td><td>{{name}}</td>    <td>{{profession}}</td></tr> {{/each}} </table> Now we are well on our way to do some true templating. You can also write your own helpers, which is beyond the scope of an introductory article. However, before we leave you, there is one cool feature of handlebars you need to know about: partials. Partials In web development, where you dynamically generate HTML to be part of a web page, it is often the case that you repetitively need to do the same thing, albeit on a different page. There is a cool feature in express-handlebars that allows you to do that very same thing: partials. Partials are templates you can refer to inside a template, using a special syntax and drastically shortening your code that way. The partials are stored in a separate folder. By default, that would be views/partials, but you can even use subfolders. Let's redo the previous example but with a partial. So, our template is going to be extremely petite: {{!-- people.handlebars inside views  --}}    {{> peoplepartial }} Notice the > sign; this is what indicates a partial. Now, here is the familiar looking partial template: {{!-- peoplepartialhandlebars inside views/partials --}} <h1>Famous California people </h1> <table> {{#each people}} <tr><td>{{first}}</td><td>{{name}}</td> <td>{{profession}}</td></tr> {{/each}} </table> And, following is the JavaScript code that triggers it: app.get('/people', function(req, res) { res.render('people', californiapeople); }); So, we give it the same context but the view that is rendered is ridiculously simplistic, as there is a partial underneath that will take care of everything. Of course, these were all examples to demonstrate how handlebars and Express can work together really well, nothing more than that. Summary In this article, we talked about using templates in web development. Then, we zoomed in on using Node.js and Express, and introduced Handlebars.js. Handlebars.js is cool, as it lets you separate logic from layout and you can use it server-side (which is where we focused on), as well as client-side. Moreover, you will still be able to use HTML for your views and layouts, unlike with other templating processors. For those of you new to Node.js, I compared it to what Le Sacre du Printemps was to music. To all of you, I recommend the recording by the Los Angeles Philharmonic and Esa-Pekka Salonen. I had season tickets for this guy and went to his inaugural concert with Mahler’s third symphony. PHP had not been written yet, but this particular performance I had heard on the radio while on the road in California, and it was magnificent. Check it out. And, also check out Express and handlebars. Resources for Article: Let's Build with AngularJS and Bootstrap The Bootstrap grid system MODx Web Development: Creating Lists
Read more
  • 0
  • 2
  • 38319

article-image-build-an-iot-application-with-azure-iot-tutorial
Gebin George
21 Jun 2018
13 min read
Save for later

Build an IoT application with Azure IoT [Tutorial]

Gebin George
21 Jun 2018
13 min read
Azure IoT makes it relatively easy to build an IoT application from scratch. In this tutorial, you'll find out how to do it. This article is an excerpt from the book, Enterprise Internet of Things Handbook, written by Arvind Ravulavaru. This book will help you work with various trending enterprise IoT platforms. End-to-end communication To get started with Azure IoT, we need to have an Azure account. If you do not have an Azure account, you can create one by navigating to this URL: https://azure.microsoft.com/en-us/free/. Once you have created your account, you can log in and navigate to the Azure portal or you can visit https://portal.azure.com to reach the required page. Setting up the IoT hub The following are the steps required for the setup. Once we are on the portal dashboard, we will be presented with the dashboard home page as illustrated here: Click on +New from the top-left-hand-side menu, then, from the Azure Marketplace, select Internet of Things | IoT Hub, as depicted in the following screenshot: Fill in the IoT hub form to create a new IoT hub, as illustrated here: I have selected F1-Free for the pricing and selected Free Trial as a Subscription, and, under Resource group, I have selected Create new and named it Pi3-DHT11-Node. Now, click on the Create button. It will take a few minutes for the IoT hub to be provisioned. You can keep an eye on the notifications to see the status. If everything goes well, on your dashboard, under the All resources tile, you should see the newly created IoT hub. Click on it and you will be taken to the IoT hub page. From the hub page, click on IoT Devices under the EXPLORERS section and you should see something similar to what is shown in the following screenshot: As you can see, there are no devices. Using the +Add button at the top, create a new device. Now, in the Add Device section, fill in the details as illustrated here: Make sure the device is enabled; else you will not be able to connect using this device ID. Once the device is created, you can click on it to see the information shown in the following screenshot: Do note the Connection string-primary key field. We will get back to this in our next section. Setting up Raspberry Pi on the DHT11 node Now that we have our device set up in Azure IoT, we are going to complete the remaining operations on the Raspberry Pi 3 to send data. Things needed The things required to set up the Raspberry Pi DHT11 node are as follows: One Raspberry Pi 3: https://www.amazon.com/Raspberry-Pi-Desktop-Starter-White/dp/B01CI58722 One breadboard: https://www.amazon.com/Solderless-Breadboard-Circuit-Circboard-Prototyping/dp/B01DDI54II/ One DHT11 sensor: https://www.amazon.com/HiLetgo-Temperature-Humidity-Arduino-Raspberry/dp/B01DKC2GQ0 Three male-to-female jumper cables: https://www.amazon.com/RGBZONE-120pcs-Multicolored-Dupont-Breadboard/dp/B01M1IEUAF/ If you are new to the world of Raspberry Pi GPIO's interfacing, take a look at Raspberry Pi GPIO Tutorial: The Basics Explained video tutorial on YouTube: https://www.youtube.com/watch?v=6PuK9fh3aL8. The steps for setting up the smart device are as follows: Connect the DHT11 sensor to the Raspberry Pi 3 as shown in the following schematic: Next, power up the Raspberry Pi 3 and log into it. On the desktop, create a new folder named Azure-IoT-Device. Open a new Terminal and cd into this newly created folder. Setting up Node.js If Node.js is not installed, please refer to the following steps: Open a new Terminal and run the following commands: $ sudo apt update $ sudo apt full-upgrade This will upgrade all the packages that need upgrades. Next, we will install the latest version of Node.js. We will be using the Node 7.x version: $ curl -sL https://deb.nodesource.com/setup_7.x | sudo -Ebash- $ sudo apt install nodejs This will take a moment to install, and, once your installation is done, you should be able to run the following commands to see the versions of Node.js and NPM: $ node -v $ npm -v Developing the Node.js device app Now we will set up the app and write the required code: From the Terminal, once you are inside the Azure-IoT-Device folder, run the following command: $ npm init -y Next, we will install azure-iot-device-mqtt from NPM (https://www.npmjs.com/package/azure-iot-device-mqtt). This module has the required client code to interface with Azure IoT. Along with this, we are going to install the azure-iot-device (https://www.npmjs.com/package/azure-iot-device) and async modules (https://www.npmjs.com/package/async). Execute the following command: $ npm install azure-iot-device-mqtt azure-iot-device async --save Next, we will install rpi-dht-sensor from NPM (https://www.npmjs.com/package/rpi-dht-sensor). This module will help to read the DHT11 temperature and humidity values. Run the following command: $ npm install rpi-dht-sensor --save Your final package.json file should look like this: { "name":"Azure-IoT-Device", "version":"1.0.0", "description":"", "main":"index.js", "scripts":{ "test":"echo"Error:notestspecified"&&exit1" }, "keywords":[], "author":"", "license":"ISC", "dependencies":{ "async":"^2.6.0", "azure-iot-device-mqtt":"^1.3.1", "rpi-dht-sensor":"^0.1.1" } } Now that we have the required dependencies installed, let's continue. Create a new file named index.js at the root of the Azure-IoT-Device folder. Your final folder structure should look similar to the following screenshot: Open index.js in any text editor and update it as illustrated in the code snippet that can be found here: https://github.com/PacktPublishing/Enterprise-Internet-of-Things-Handbook. In the previous code, we are creating a new MQTTS client from the connectionString. You can get the value of this connection string from IoT Hub | IoT Devices | Pi3-DHT11-Node | Device Details | Connection string-primary key as shown in the following screenshot: Update the connectionString in our code with the previous values. Going back to the code, we are using client.open(connectCallback) to connect to the Azure MQTT broker for our IoT hub, and, once the connection has been made successfully, we call the connectCallback(). In the connectCallback(), we get the device twin using client.getTwin(). Once we have gotten the device twin, we will start collecting the data, send this data to other clients listening to this device using client.sendEvent(), and then send the copy to the device twin using twin.properties.reported.update, so any new client that joins gets the latest saved data. Now, save the file and run the sudo node index.js command. We should see the command output in the console of Raspberry Pi 3: The device has successfully connected, and we are sending the data to both the device twin and the MQTT event. Now, if we head back to the Azure IoT portal, navigate to IoT Hub | IoT Device | Pi3-DHT11-Node | Device Details and click on the device twin, we should see the last data record that was sent by the Raspberry Pi 3, as shown in the following image: Now that we are able to send the data from the device, let's read this data from another MQTT client. Reading the data from the IoT Thing To read the data from the device, you can either use the same Raspberry Pi 3 or another computer. I am going to use my MacBook as a client that is interested in the data sent by the device: Create a folder named test_client. Inside the test_client folder, run the following command: $ npm init --yes Next, install the azure-event-hubs module (https://www.npmjs.com/package/azure-event-hubs) using the following command: $ npm install azure-event-hubs --save Create a file named index.js inside the test_client folder and update it as detailed in the following code snippet: var EventHubClient = require('azure-event-hubs').Client; var connectionString = 'HostName=Pi3-DHT11-Nodes.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=J0MTJVy+RFkSaaenfegGMJY3XWKIpZp2HO4eTwmUNoU='; constTAG = '[TESTDEVICE]>>>>>>>>>'; var printError = function(err) { console.log(TAG, err); }; var printMessage = function(message) { console.log(TAG, 'Messagereceived:', JSON.stringify(message.body)); }; var client = EventHubClient.fromConnectionString(connectionString); client.open() .then(client.getPartitionIds.bind(client)) .then(function(partitionIds) { returnpartitionIds.map(function(partitionId) { returnclient.createReceiver('$Default', partitionId, { 'startAfterTime': Date.now() }) .then(function(receiver) { //console.log(TAG,'Createdpartitionreceiver:'+partitionId) console.log(TAG, 'Listening...'); receiver.on('errorReceived', printError); receiver.on('message', printMessage); }); }); }) .catch(printError); In the previous code snippet, we have a connectionString variable. To get the value of this variable, head back to the Azure portal, via IoT Hub | Shared access policies | iothubowner | Connection string-primary key as illustrated in the following screenshot: Copy the value from the Connection string-primary key field and update the code. Finally, run the following command: $ node index.js The following console screenshot shows the command's output: This way, any client that is interested in the data from this device can use this approach to get the latest data. You can also use an MQTT library on the client side to do the same, but do keep in mind that this is not advisable as the connection string is exposed. Instead, you can have a backend micro service that can achieve the same for you and then expose the data via HTTPS. With this, we conclude the section on posting data to Azure IoT and fetching that data. In the next section, we are going to work with building a dashboard for our data. Building a dashboard Now that we have seen how a client can read data from our device on demand, we will move to building a dashboard on which we will show data in real time. For this, we are going to use an Azure stream analytics job and Power BI. Azure stream analytics Azure stream analytics is a managed event-processing engine set up with real-time analytic computations on streaming data. It can gather data coming from various sources, collate it, and stream it into a different source. Using stream analytics, we can examine high volumes of data streamed from devices, extract information from that data stream, and identify patterns, trends, and relationships. Read more about Azure stream analytics. Power BI Power BI is a suite of business-analytics tools used to analyze data and share insights. A Power BI dashboard updates in real time and provides a single interface for exploring all the important metrics. With one click, users can explore the data behind their dashboard using intuitive tools that make finding answers easy. Creating dashboards and accessing them across various sources is also quite easy. Read more about Power BI. As we have seen in the architecture section, we are going to follow the steps given in the next section to create a dashboard in Power BI. Execution steps These are the steps that need to be followed: Create a new Power BI account. Set up a new consumer group for events (built-in endpoint). Create a stream analytics job. Set up input and outputs. Build the query to stream data from the Azure IoT hub to Power BI. Visualize the datasets in Power BI and build a dashboard. So let's get started. Signing up to Power BI Navigate to the Power BI sign-in page, and use the Sign up free option and get started today form on this page to create an account. Once an account has been created, validate the account. Log in to Power BI with your credentials and you will land on your default workspace. At the time of writing, Power BI needs an official email to create an account. Setting up events Now that we have created a new Power BI, let's set up the remaining pieces: Head back to https://portal.azure.com and navigate to the IoT hub we have created. From the side menu inside the IoT hub page, select Endpoints then Events under the Built-in endpoints section. When the form opens, under the Consumer groups section, create a new consumer group with the name, pi3-dht11-stream, as illustrated, and then click on the Save button to save the changes: Next, we will create a new stream analytics job. Creating a stream analytics job Let's see how to create a stream analytics job by following these steps: Now that the IoT hub setup is done, head back to the dashboard. From the top-left menu, click on +New, then Internet of Things and Stream Analytics job, as shown in the following screenshot: Fill in the New Stream Analytics job form, as illustrated here: Then click on the Create button. It will take a couple of minutes to create a new job. Do keep an eye on the notification section for any updates. Once the job has been created, it will appear on your dashboard. Select the job that was created and navigate to the Inputs section under JOB TOPOLOGY, as shown here: Click on +Add stream input and select IoT Hub, as shown in the previous screenshot. Give the name pi3dht11iothub to the input alias, and click on Save. Next, navigate to the Outputs section under JOB TOPOLOGY, as shown in the following screenshot: Click +Add and select Power BI, as shown in the previous screenshot. Fill in the details given in the following table: Field Value Output alias powerbi Group workspace My workspace (after completing the authorization step) Dataset name pi3dht11 Table name dht11 Click the Authorize button to authorize the IoT hub to create the table and datasets, as well as to stream data. The final form before creation should look similar to this: Click on Save. Next, click on Query under JOB TOPOLOGY and update it as depicted in the following screenshot: Now, click on the Save button. Next, head over to the Overview section, click on Start, select Now, and then click on Start: Once the job starts successfully, you should see the Status of Running instead of Starting. Running the device Now that the entire setup is done, we will start pumping data into the Power BI. Head back to the Raspberry Pi 3 that was sending the DHT11 temperature and humidity data, and run our application. We should see the data being published to the IoT hub as the Data Sent log gets printed: Building the visualization Now that the data is being pumped to Power BI via the Azure IoT hub and stream analytics, we will start building the dashboard: Log in to Power BI, navigate to the My Workspace that we selected when we created the Output in the Stream Analytics job, and select Datasets. We should see something similar to the screenshot illustrated here: Using the first icon under the ACTIONS column, for the pi3dht11 dataset, create a new report. When you are in the report page, under VISUALIZATIONS, select line chart, drag EventEnqueuedUtcTime to the Axis field, and set the temp and humd fields to the values as shown in the following screenshot: You can also see the graph data in real time. You can save this report for future reference. This wraps up the section of building a visualization using Azure IoT hub, a stream analytics job, and Power BI. With this, we have seen the basic features and implementation of an end to end IoT application with Azure IoT platform. If you found this post useful, do check out the book, Enterprise Internet of Things Handbook, to build end-to-end IoT solutions using popular IoT platforms. Introduction to IOT Introducing IoT with Particle's Photon and Electron Five developer centric sessions at IoT World 2018
Read more
  • 0
  • 3
  • 38283
article-image-how-to-install-keras-on-docker-and-cloud-ml
Amey Varangaonkar
20 Dec 2017
3 min read
Save for later

How to Install Keras on Docker and Cloud ML

Amey Varangaonkar
20 Dec 2017
3 min read
[box type="note" align="" class="" width=""]The following extract is taken from the book Deep Learning with Keras, written by Antonio Gulli and Sujit Pal. It contains useful techniques to train effective deep learning models using the highly popular Keras library.[/box] Keras is a deep learning library which can be used on the enterprise platform, by deploying it on a container. In this article, we see how to install Keras on Docker and Google’s Cloud ML. Installing Keras on Docker One of the easiest ways to get started with TensorFlow and Keras is running in a Docker container. A convenient solution is to use a predefined Docker image for deep learning created by the community that contains all the popular DL frameworks (TensorFlow, Theano, Torch, Caffe, and so on). Refer to the GitHub repository at https://github.com/saiprashanths/dl-docker for the code files. Assuming that you already have Docker up and running (for more information, refer to https://www.docker.com/products/overview), installing it is pretty simple and is shown as follows: The following screenshot, says something like, after getting the image from Git, we build the Docker image: In this following screenshot, we see how to run it: From within the container, it is possible to activate support for Jupyter Notebooks (for more information, refer to http://jupyter.org/): Access it directly from the host machine on port: It is also possible to access TensorBoard (for more information, refer to https://www.tensorflow.org/how_tos/summaries_and_tensorboard/) with the help of the command in the screenshot that follows, which is discussed in the next section: After running the preceding command, you will be redirected to the following page: Installing Keras on Google Cloud ML Installing Keras on Google Cloud is very simple. First, we can install Google Cloud (for the downloadable file, refer to https://cloud.google.com/sdk/), a command-line interface for Google Cloud Platform; then we can use CloudML, a managed service that enables us to easily build machine, learning models with TensorFlow. Before using Keras, let's use Google Cloud with TensorFlow to train an MNIST example available on GitHub. The code is local and training happens in the cloud: In the following screenshot, you can see how to run a training session: We can use TensorBoard to show how cross-entropy decreases across iterations: In the next screenshot, we see the graph of cross-entropy: Now, if we want to use Keras on the top of TensorFlow, we simply download the Keras source from PyPI (for the downloadable file, refer to https://pypi.python.org/pypi/Keras/1.2.0 or later versions) and then directly use Keras as a CloudML package solution, as in the following example: Here, trainer.task2.py is an example script: from keras.applications.vgg16 import VGG16 from keras.models import Model from keras.preprocessing import image from keras.applications.vgg16 import preprocess_input import numpy as np # pre-built and pre-trained deep learning VGG16 model base_model = VGG16(weights='imagenet', include_top=True) for i, layer in enumerate(base_model.layers): print (i, layer.name, layer.output_shape) Thus we saw, how fairly easy it is to set up and run Keras on a Docker container and Cloud ML. If this article interested you, make sure to check out our book Deep Learning with Keras, where you can learn to install Keras on other popular platforms such as Amazon Web Services and Microsoft Azure.  
Read more
  • 0
  • 0
  • 38206

article-image-introducing-generative-adversarial-networks
Amey Varangaonkar
11 Dec 2017
6 min read
Save for later

Implementing a simple Generative Adversarial Network (GANs)

Amey Varangaonkar
11 Dec 2017
6 min read
[box type="note" align="" class="" width=""]The following excerpt is taken from Chapter 2 - Learning Features with Unsupervised Generative Networks of the book Deep Learning with Theano, written by Christopher Bourez. This book talks about modeling and training effective deep learning models with Theano, a popular Python-based deep learning library. [/box] In this article, we introduce you to the concept of Generative Adversarial Networks, a popular class of Artificial Intelligence algorithms used in unsupervised machine learning. Code files for this particular chapter are available for download towards the end of the post. Generative adversarial networks are composed of two models that are alternatively trained to compete with each other. The generator network G is optimized to reproduce the true data distribution, by generating data that is difficult for the discriminator D to differentiate from real data. Meanwhile, the second network D is optimized to distinguish real data and synthetic data generated by G. Overall, the training procedure is similar to a two-player min-max game with the following objective function: Here, x is real data sampled from real data distribution, and z the noise vector of the generative model. In some ways, the discriminator and the generator can be seen as the police and the thief: to be sure the training works correctly, the police is trained twice as much as the thief. Let's illustrate GANs with the case of images as data. In particular, let's again take our example from Chapter 2, Classifying Handwritten Digits with a Feedforward Network about MNIST digits, and consider training a generative adversarial network, to generate images, conditionally on the digit we want. The GAN method consists of training the generative model using a second model, the discriminative network, to discriminate input data between real and fake. In this case, we can simply reuse our MNIST image classification model as discriminator, with two classes, real or fake, for the prediction output, and also condition it on the label of the digit that is supposed to be generated. To condition the net on the label, the digit label is concatenated with the inputs: def conv_cond_concat(x, y): return T.concatenate([x, y*T.ones((x.shape[0], y.shape[1], x.shape[2], x.shape[3]))], axis=1) def discrim(X, Y, w, w2, w3, wy): yb = Y.dimshuffle(0, 1, 'x', 'x') X = conv_cond_concat(X, yb) h = T.nnet.relu(dnn_conv(X, w, subsample=(2, 2), border_mode=(2, 2)), alpha=0.2 ) h = conv_cond_concat(h, yb) h2 = T.nnet.relu(batchnorm(dnn_conv(h, w2, subsample=(2, 2), border_mode=(2, 2))), alpha=0.2) h2 = T.flatten(h2, 2) h2 = T.concatenate([h2, Y], axis=1) h3 = T.nnet.relu(batchnorm(T.dot(h2, w3))) h3 = T.concatenate([h3, Y], axis=1) y = T.nnet.sigmoid(T.dot(h3, wy)) return y Note the use of two leaky rectified linear units, with a leak of 0.2, as activation for the first two convolutions. To generate an image given noise and label, the generator network consists of a stack of deconvolutions, using an input noise vector z that consists of 100 real numbers ranging from 0 to 1: To create a deconvolution in Theano, a dummy convolutional forward pass is created, which gradient is used as deconvolution: def deconv(X, w, subsample=(1, 1), border_mode=(0, 0), conv_ mode='conv'): img = gpu_contiguous(T.cast(X, 'float32')) kerns = gpu_contiguous(T.cast(w, 'float32')) desc = GpuDnnConvDesc(border_mode=border_mode, subsample=subsample, conv_mode=conv_mode)(gpu_alloc_empty(img.shape[0], kerns.shape[1], img.shape[2]*subsample[0], img.shape[3]*subsample[1]).shape, kerns. shape) out = gpu_alloc_empty(img.shape[0], kerns.shape[1], img. shape[2]*subsample[0], img.shape[3]*subsample[1]) d_img = GpuDnnConvGradI()(kerns, img, out, desc) return d_img def gen(Z, Y, w, w2, w3, wx): yb = Y.dimshuffle(0, 1, 'x', 'x') Z = T.concatenate([Z, Y], axis=1) h = T.nnet.relu(batchnorm(T.dot(Z, w))) h = T.concatenate([h, Y], axis=1) h2 = T.nnet.relu(batchnorm(T.dot(h, w2))) h2 = h2.reshape((h2.shape[0], ngf*2, 7, 7)) h2 = conv_cond_concat(h2, yb) h3 = T.nnet.relu(batchnorm(deconv(h2, w3, subsample=(2, 2), border_mode=(2, 2)))) h3 = conv_cond_concat(h3, yb) x = T.nnet.sigmoid(deconv(h3, wx, subsample=(2, 2), border_ mode=(2, 2))) return x Real data is given by the tuple (X,Y), while generated data is built from noise and label (Z,Y): X = T.tensor4() Z = T.matrix() Y = T.matrix() gX = gen(Z, Y, *gen_params) p_real = discrim(X, Y, *discrim_params) p_gen = discrim(gX, Y, *discrim_params) Generator and discriminator models compete during adversarial learning: The discriminator is trained to label real data as real (1) and label generated data as generated (0), hence minimizing the following cost function: d_cost = T.nnet.binary_crossentropy(p_real, T.ones(p_real.shape)).mean() + T.nnet.binary_crossentropy(p_gen, T.zeros(p_gen.shape)). mean() The generator is trained to deceive the discriminator as much as possible. The training signal for the generator is provided by the discriminator network (p_gen) to the generator: g_cost = T.nnet.binary_crossentropy(p_gen,T.ones(p_gen.shape)). mean() The same as usual follows. Cost with respect to the parameters for each model is computed and training optimizes the weights of each model alternatively, with two times more the discriminator. In the case of GANs, competition between discriminator and generator does not lead to decreases in each loss. From the first epoch: To the 45th epoch: Generated examples look closer to real ones: Generative models, and especially Generative Adversarial Networks are currently the trending areas of Deep Learning. It has also found its way in a few practical applications as well.  For example, a generative model can successfully be trained to generate the next most likely video frames by learning the features of the previous frames. Another popular example where GANs can be used is, search engines that predict the next likely word before it is even entered by the user, by studying the sequence of the previously entered words. If you found this excerpt useful, do check out more comprehensive coverage of popular deep learning topics in our book  Deep Learning with Theano. [box type="download" align="" class="" width=""] Download files [/box]  
Read more
  • 0
  • 0
  • 38189

article-image-how-to-deploy-nodejs-application-to-the-web-using-heroku
Sunith Shetty
26 Apr 2018
19 min read
Save for later

How to deploy a Node.js application to the web using Heroku

Sunith Shetty
26 Apr 2018
19 min read
Heroku is a tool that helps you manage cloud hosted web applications. It's a really great service. It makes creating, deploying, and updating apps really easy. Now Heroku, like GitHub, does not require a credit card to sign up and there is a free tier, which we'll use. They have paid plans for just about everything, but we can get away with the free tier for everything we'll do in this section. In this tutorial, you'll learn to deploy your live Node.js app to the Web using Heroku. By the end of this tutorial, you'll have the URL that you can share with anybody to view the application from their browser. Installing Heroku command-line tools To kick things off, we'll open up the browser and go to Heroku's website here. Here we can go ahead and sign up for a new account. Take a quick moment to either log in to your existing one or sign up for a new one. Once logged in, it'll show you the dashboard. Now your dashboard will look something like this: Although there might be a greeting telling you to create a new application, which you can ignore. I have a bunch of apps. You might not have these. That is perfectly fine. The next thing we'll do is install the Heroku command-line tools. This will let us create apps, deploy apps, open apps, and do all sorts of really cool stuff from the Terminal, without having to come into the web app. That will save us time and make development a lot easier. We can grab the download by going to toolbelt.heroku.com. Here we're able to grab the installer for whatever operating system, you happen to be running on. So, let's start the download. It's a really small download so it should happen pretty quickly. Once it's done, we can go ahead and run through the process: This is a simple installer where you just click on Install. There is no need to customize anything. You don't have to enter any specific information about your Heroku account. Let's go ahead and complete the installer. This will give us a new command from the Terminal that we can execute. Before we can do that, we do have to log in locally in the Terminal and that's exactly what we'll do next. Log in to Heroku account locally Now we will start off the Terminal. If you already have it running, you might need to restart it in order for your operating system to recognize the new command. You can test that it got installed properly by running the following command: heroku --help When you run this command, you'll see that it's installing the CLI for the first time and then we'll get all the help information. This will tell us what commands we have access to and exactly how they work: Now we will need to log in to the Heroku account locally. This process is pretty simple. In the preceding code output, we have all of the commands available and one of them happens to be login. We can run heroku login just like this to start the process: heroku login I'll run the login command and now we just use the email and password that we had set up before: I'll type in my email and password. Typing for Password is hidden because it's secure. And when I do that you see Logged in as garyngreig@gmail.com shows up and this is fantastic: Now we're logged in and we're able to successfully communicate between our machine's command line and the Heroku servers. This means we can get started creating and deploying applications. Getting SSH key to Heroku Now before going ahead, we'll use the clear command to clear the Terminal output and get our SSH key on Heroku, kind of like what we did with GitHub, only this time we can do it via the command line. So it's going to be a lot easier. In order to add our local keys to Heroku, we'll run the heroku keys:add command. This will scan our SSH directory and add the key up: heroku keys:add Here you can see it found a key the id_rsa.pub file: Would you like to upload it to Heroku? Type Yes and hit enter: Now we have our key uploaded. That is all it took. Much easier than it was to configure with GitHub. From here, we can use the heroku keys command to print all the keys currently on our account: heroku keys We could always remove them using heroku keys:remove command followed by the email related to that key. In this case, we'll keep the Heroku key that we have. Next up, we can test our connection using SSH with the v flag and git@heroku.com: ssh -v git@heroku.com This will communicate with the Heroku servers: As shown, we can see it's asking that same question: The authenticity of the host 'heroku.com' can't be established, Are you sure you want to continue connecting? Type Yes. You will see the following output: Now when you run that command, you'll get a lot of cryptic output. What you're looking for is authentication succeeded and then public key in parentheses. If things did not go well, you'll see the permission denied message with public key in parentheses. In this case, the authentication was successful, which means we are good to go. I'll run clear again, clearing the Terminal output. Setting up in the application code for Heroku Now we can turn our attention towards the application code because before we can deploy to Heroku, we will need to make two changes to the code. These are things that Heroku expects your app to have in place in order to run properly because Heroku does a lot of things automatically, which means you have to have some basic stuff set up for Heroku to work. It's not too complex—some really simple changes, a couple one-liners. Changes in the server.js file First up in the server.js file down at the very bottom of the file, we have the port and our app.listen statically coded inside server.js: app.listen(3000, () => { console.log('Server is up on port 3000'); }); We need to make this port dynamic, which means we want to use a variable. We'll be using an environment variable that Heroku is going to set. Heroku will tell your app which port to use because that port will change as you deploy your app, which means that we'll be using that environment variable so we don't have to swap out our code every time we want to deploy. With environment variables, Heroku can set a variable on the operating system. Your Node app can read that variable and it can use it as the port. Now all machines have environment variables. You can actually view the ones on your machine by running the env command on Linux or macOS or the set command on Windows. What you'll get when you do that is a really long list of key-value pairs, and this is all environment variables are: Here, we have a LOGNAME environment variable set to Andrew. I have a HOME environment variable set to my home directory, all sorts of environment variables throughout my operating system. One of these that Heroku is going to set is called PORT, which means we need to go ahead and grab that port variable and use it in server.js instead of 3000. Up at the very top of the server.js file, we'd to make a constant called port, and this will store the port that we'll use for the app: const express = require('express');. const hbs = require('hbs'); const fs = require('fs'); const port Now the first thing we'll do is grab a port from process.env. The process.env is an object that stores all our environment variables as key-value pairs. We're looking for one that Heroku is going to set called PORT: const port = process.env.PORT; This is going to work great for Heroku, but when we run the app locally, the PORT environment variable is not going to exist, so we'll set a default using the OR (||) operator in this statement. If process.env.port does not exist, we'll set port equal to 3000 instead: const port = process.env.PORT || 3000; Now we have an app that's configured to work with Heroku and to still run locally, just like it did before. All we have to do is take the PORT variable and use that in app.listen instead of 3000. As shown, I'm going to reference port and inside our message, I'll swap it out for template strings and now I can replace 3000 with the injected port variable, which will change over time: app.listen(port, () => { console.log(`Server is up on port ${port}`); }); With this in place, we have now fixed the first problem with our app. I'll now run node server.js from the Terminal. node server.js We still get the exact same message: Server is up on port 3000, so your app will still works locally as expected: Changes in the package.json file Next up, we have to specify a script in package.json. Inside package.json, you might have noticed we have a scripts object, and in there we have a test script. This gets set by default for npm: We can create all sorts of scripts inside the scripts object that do whatever we like. A script is nothing more than a command that we run from the Terminal, so we could take this command, node server.js, and turn it into a script instead, and that's exactly what we're going to do. Inside the scripts object, we'll add a new script. The script needs to be called start: This is a very specific, built-in script and we'll set it equal to the command that starts our app. In this case, it will be node server.js: "start": "node server.js" This is necessary because when Heroku tries to start our app, it will not run Node with your file name because it doesn't know what your file name is called. Instead, it will run the start script and the start script will be responsible for doing the proper thing; in this case, booting up that server file. Now we can run our app using that start script from the Terminal by using the following command: npm start When I do that, we get a little output related to npm and then we get Server is up on port 3000. The big difference is that we are now ready for Heroku. We could also run the test script using from the Terminal npm test: npm test Now, we have no tests specified and that is expected: Making a commit in Heroku The next step in the process will be to make the commit and then we can finally start getting it up on the Web. First up, git status. When we run git status, we have something a little new: Instead of new files, we have modified files here as shown in the code output here. We have a modified package.json file and we have a modified server.js file. These are not going to be committed if we were to run a git commit just yet; we still have to use git add. What we'll do is run git add with the dot as the next argument. Dot is going to add every single thing showing up and get status to the next commit. Now I only recommend using the syntax of everything you have listed in the Changes not staged for commit header. These are the things you actually want to commit, and in our case, that is indeed what we want. If I run git add and then a rerun git status, we can now see what is going to be committed next, under the Changes to be committed header: Here we have our package.json file and the server.js file. Now we can go ahead and make that commit. I'll run a git commit command with the m flag so we can specify our message, and a good message for this commit would be something like Setup start script and heroku Port: git commit -m 'Setup start script and heroku port' Now we can go ahead and run that command, which will make the commit. Now we can go ahead and push that up to GitHub using the git push command, and we can leave off the origin remote because the origin is the default remote. I'll go ahead and run the following command: git push This will push it up to GitHub, and now we are ready to actually create the app, push our code up, and view it over in the browser: Running the Heroku create command The next step in the process will be to run a command called heroku create from the Terminal. heroku create needs to get executed from inside your application: heroku create Just like we run our Git commands, when I run heroku create, a couple things are going to happen: First up, it's going to make a real new application over in the Heroku web app It's also going to add a new remote to your Git repository Now remember we have an origin remote, which points to our GitHub repository. We'll have a Heroku remote, which points to our Heroku Git repository. When we deploy to the Heroku Git repository, Heroku is going to see that. It will take the changes and it will deploy them to the Web. When we run Heroku create, all of that happens: Now we do still have to push up to this URL in order to actually do the deploying process, and we can do that using git push followed by heroku: git push heroku The brand new remote was just added because we ran heroku create. Now pushing it this time around will go through the normal process. You'll then start seeing some logs. These are logs coming back from Heroku letting you know how your app is deploying. It's going through the entire process, showing you what happens along the way. This will take about 10 seconds and at the very end we have a success message—Verifying deploy... done: It also verified that the app was deployed successfully and that did indeed pass. From here we actually have a URL we can visit (https://sleepy-retreat-32096.herokuapp.com/). We can take it, copy it, and paste it in the browser. What I'll do instead is use the following command: heroku open The heroku open will open up the Heroku app in the default browser. When I run this, it will switch over to Chrome and we get our application showing up just as expected: We can switch between pages and everything works just like it did locally. Now we have a URL and this URL was given to us by Heroku. This is the default way Heroku generates app URLs. If you have your own domain registration company, you can go ahead and configure its DNS to point to this application. This will let you use a custom URL for your Heroku app. You'll have to refer to the specific instructions for your domain registrar in order to do that, but it can indeed be done. Now that we have this in place, we have successfully deployed our Node applications live to Heroku, and this is just fantastic. In order to do this, all we had to do is make a commit to change our code and push it up to a new Git remote. It could not be easier to deploy our code. You can also manage your application by going back over to the Heroku dashboard. If you give it a refresh, you should see that brand new URL somewhere on the dashboard. Remember mine was sleepy retreat. Yours is going to be something else. If I click on the sleepy retreat, I can view the app page: Here we can do a lot of configuration. We can manage Activity and Access so we can collaborate with others. We have metrics, we have Resources, all sorts of really cool stuff. With this in place, we are now done with our basic deploying section. In the next section, your challenge will be to go through that process again. You'll add some changes to the Node app. You'll commit them, deploy them, and view them live in the Web. We'll get started by creating the local changes. That means I'll register a new URL right here using app.get. We'll create a new page/projects, which is why I have that as the route for my HTTP get handler. Inside the second argument, we can specify our callback function, which will get called with request and response, and like we do for the other routes above, the root route and our about route, we'll be calling response.render to render our template. Inside the render arguments list, we'll provide two. The first one will be the file name. The file doesn't exist, but we can still go ahead and call render. I'll call it projects.hbs, then we can specify the options we want to pass to the template. In this case, we'll set page title, setting it equal to Projects with a capital P. Excellent! Now with this in place, the server file is all done. There are no more changes there. What I'll do is go ahead and go to the views directory, creating a new file called projects.hbs. In here, we'll be able to configure our template. To kick things off, I'm going to copy the template from the about page. Since it's really similar, I'll copy it. Close about, paste it into projects, and I'm just going to change this text to project page text would go here. Then we can save the file and make our last change. The last thing we want to do is update the header. We now have a brand new projects page that lives at /projects. So we'll want to go ahead and add that to the header links list. Right here, I'll create a new paragraph tag and then I'll make an anchor tag. The text for the link will be Projects with a capital P and the href, which is the URL to visit when that link is clicked. We'll set that equal to /projects, just like we did for about, where we set it equal to /about. Now that we have this in place, all our changes are done and we are ready to test things out locally. I'll fire up the app locally using Node with server.js as the file. To start, we're up on localhost 3000. So over in the browser, I can move to the localhost tab, as opposed to the Heroku app tab, and click on Refresh. Right here we have Home, which goes to home, we have About which goes to about, and we have Projects which does indeed go to /projects, rendering the projects page. Project page text would go here. With this in place we're now done locally. We have the changes, we've tested them, now it's time to go ahead and make that commit. That will happen over inside the Terminal. I'll shut down the server and run Git status. This will show me all the changes to my repository as of the last commit. I have two modified files: the server file and the header file, and I have my brand new projects file. All of this looks great. I want to add all of this to the next commit, so I can use a Git add with the . to do just that. Now before I actually make the commit, I do like to test that the proper things got added by running Git status. Right here I can see my changes to be committed are showing up in green. Everything looks great. Next up, we'll run a Git commit to actually make the commit. This is going to save all of the changes into the Git repository. A message for this one would be something like adding a project page. With a commit made, the next thing you needed to do was push it up to GitHub. This will back our code up and let others collaborate on it. I'll use Git push to do just that. Remember we can leave off the origin remote as origin is the default remote, so if you leave off a remote it'll just use that anyway. With our GitHub repository updated, the last thing to do is deploy to Heroku and we do that by pushing up the Git repository, using Git push, to the Heroku remote. When we do this, we get our long list of logs as the Heroku server goes through the process of installing our npm modules, building the app, and actually deploying it. Once it's done, we'll get brought back to the Terminal like we are here, and then we can open up the URL in the\ browser. Now I can copy it from here or run Heroku open. Since I already have a tab open with the URL in place, I'll simply give it a refresh. Now you might have a little delay as you refresh your app. Sometimes starting up the app right after a new app was deployed can take about 10 to 15 seconds. That will only happen as you first visit it. Other times where you click on the Refresh button, it should reload instantly. Now we have the projects page and if I visit it, everything looks awesome. The navbar is working great and the projects page is indeed rendering at /projects. With this in place, we are now done. We've gone through the process of adding a new feature, testing it locally, making a Git commit, pushing it up to GitHub, and deploying it to Heroku. We now have a workflow for building real-world web applications using Node.js. This tutorial has been taken from Learning Node.js Development. More Heroku tutorials Deploy a Game to Heroku Managing Heroku from the command line
Read more
  • 0
  • 0
  • 38189
article-image-functions-arduino
Packt
02 Mar 2017
13 min read
Save for later

Functions with Arduino

Packt
02 Mar 2017
13 min read
In this article by Syed Omar Faruk Towaha, the author of the book Learning C for Arduino, we will learn about functions and file handling with Arduino. We learned about loops and conditions. Let’s begin out journey into Functions with Arduino. (For more resources related to this topic, see here.) Functions Do you know how to make instant coffee? Don’t worry; I know. You will need some water, instant coffee, sugar, and milk or creamer. Remember, we want to drink coffee, but we are doing something that makes coffee. This procedure can be defined as a function of coffee making. Let’s finish making coffee now. The steps can be written as follows: Boil some water. Put some coffee inside a mug. Add some sugar. Pour in boiled water. Add some milk. And finally, your coffee is ready! Let’s write a pseudo code for this function: function coffee (water, coffee, sugar, milk) { add coffee beans; add sugar; pour boiled water; add milk; return coffee; } In our pseudo code we have four items (we would call them parameters) to make coffee. We did something with our ingredients, and finally, we got our coffee, right? Now, if anybody wants to get coffee, he/she will have to do the same function (in programming, we will call it calling a function) again. Let’s move into the types of functions. Types of functions A function returns something, or a value, which is called the return value. The return values can be of several types, some of which are listed here: Integers Float Double Character Void Boolean Another term, argument, refers to something that is passed to the function and calculated or used inside the function. In our previous example, the ingredients passed to our coffee-making process can be called arguments (sugar, milk, and so on), and we finally got the coffee, which is the return value of the function. By definition, there are two types of functions. They are, a system-defined function and a user-defined function. In our Arduino code, we have often seen the following structure: void setup() { } void loop() { } setup() and loop() are also functions. The return type of these functions is void. Don’t worry, we will discuss the type of function soon. The setup() and loop() functions are system-defined functions. There are a number of system-defined functions. The user-defined functions cannot be named after them. Before going deeper into function types, let’s learn the syntax of a function. Functions can be as follows: void functionName() { //statements } Or like void functionName(arg1, arg2, arg3) { //statements } So, what’s the difference? Well, the first function has no arguments, but the second function does. There are four types of function, depending on the return type and arguments. They are as follows: A function with no arguments and no return value A function with no arguments and a return value A function with arguments and no return value A function with arguments and a return value Now, the question is, can the arguments be of any type? Yes, they can be of any type, depending on the function. They can be Boolean, integers, floats, or characters. They can be a mixture of data types too. We will look at some examples later. Now, let’s define and look at examples of the four types of function we just defined. Function with no arguments and no return value, these functions do not accept arguments. The return type of these functions is void, which means the function returns nothing. Let me clear this up. As we learned earlier, a function must be named by something. The naming of a function will follow the rule for the variable naming. If we have a name for a function, we need to define its type also. It’s the basic rule for defining a function. So, if we are not sure of our function’s type (what type of job it will do), then it is safe to use the void keyword in front of our function, where void means no data type, as in the following function: void myFunction(){ //statements } Inside the function, we may do all the things we need. Say we want to print I love Arduino! ten times if the function is called. So, our function must have a loop that continues for ten times and then stops. So, our function can be written as follows: void myFunction() { int i; for (i = 0; i < 10; i++) { Serial.println(“I love Arduino!“); } } The preceding function does not have a return value. But if we call the function from our main function (from the setup() function; we may also call it from the loop() function, unless we do not want an infinite loop), the function will print I love Arduino! ten times. No matter how many times we call, it will print ten times for each call. Let’s write the full code and look at the output. The full code is as follows: void myFunction() { int i; for (i = 0; i < 10; i++) { Serial.println(“I love Arduino!“); } } void setup() { Serial.begin(9600); myFunction(); // We called our function Serial.println(“................“); //This will print some dots myFunction(); // We called our function again } void loop() { // put your main code here, to run repeatedly: } In the code, we placed our function (myFunction) after the loop() function. It is a good practice to declare the custom function before the setup() loop. Inside our setup() function, we called the function, then printed a few dots, and finally, we called our function again. You can guess what will happen. Yes, I love Arduino! will be printed ten times, then a few dots will be printed, and finally, I love Arduino! will be printed ten times. Let’s look at the output on the serial monitor: Yes. Your assumption is correct! Function with no arguments and a return value In this type of function, no arguments are passed, but they return a value. You need to remember that the return value depends on the type of the function. If you declare a function as an integer function, the return value’s type will have to have be an integer also. If you declare a function as a character, the return type must be a character. This is true for all other data types as well. Let’s look at an example. We will declare an integer function, where we will define a few integers. We will add them and store them to another integer, and finally, return the addition. The function may look as follows: int addNum() { int a = 3, b = 5, c = 6, addition; addition = a + b + c; return addition; } The preceding function should return 14. Let’s store the function’s return value to another integer type of variable in the setup() function and print in on the serial monitor. The full code will be as follows: void setup() { Serial.begin(9600); int fromFunction = addNum(); // added values to an integer Serial.println(fromFunction); // printed the integer } void loop() { } int addNum() { int a = 3, b = 5, c = 6, addition; //declared some integers addition = a + b + c; // added them and stored into another integers return addition; // Returned the addition. } The output will look as follows: Function with arguments and no return value This type of function processes some arguments inside the function, but does not return anything directly. We can do the calculations inside the function, or print something, but there will be no return value. Say we need find out the sum of two integers. We may define a number of variables to store them, and then print the sum. But with the help of a function, we can just pass two integers through a function; then, inside the function, all we need to do is sum them and store them in another variable. Then we will print the value. Every time we call the function and pass our values through it, we will get the sum of the integers we pass. Let’s define a function that will show the sum of the two integers passed through the function. We will call the function sumOfTwo(), and since there is no return value, we will define the function as void. The function should look as follows: void sumOfTwo(int a, int b) { int sum = a + b; Serial.print(“The sum is “ ); Serial.println(sum); } Whenever we call this function with proper arguments, the function will print the sum of the number we pass through the function. Let’s look at the output first; then we will discuss the code: We pass the arguments to a function, separating them with commas. The sequence of the arguments must not be messed up while we call the function. Because the arguments of a function may be of different types, if we mess up while calling, the program may not compile and will not execute correctly: Say a function looks as follows: void myInitialAndAge(int age, char initial) { Serial.print(“My age is “); Serial.println(age); Serial.print(“And my initial is “); Serial.print(initial); } Now, we must call the function like so: myInitialAndAge(6,’T’); , where 6 is my age and T is my initial. We should not do it as follows: myInitialAndAge(‘T’, 6);. We called the function and passed two values through it (12 and 24). We got the output as The sum is 36. Isn’t it amazing? Let’s go a little bit deeper. In our function, we declared our two arguments (a and b) as integers. Inside the whole function, the values (12 and 24) we passed through the function are as follows: a = 12 and b =24; If we called the function this sumOfTwo(24, 12), the values of the variables would be as follows: a = 24 and b = 12; I hope you can now understand the sequence of arguments of a function. How about an experiment? Call the sumOfTwo() function five times in the setup() function, with different values of a and b, and compare the outputs. Function with arguments and a return value This type of function will have both the arguments and the return value. Inside the function, there will be some processing or calculations using the arguments, and later, there would be an outcome, which we want as a return value. Since this type of function will return a value, the function must have a type. Let‘s look at an example. We will write a function that will check if a number is prime or not. From your math class, you may remember that a prime number is a natural number greater than 1 that has no positive divisors other than 1 and itself. The basic logic behind checking whether a number is prime or not is to check all the numbers starting from 2 to the number before the number itself by dividing the number. Not clear? Ok, let’s check if 9 is a prime number. No, it is not a prime number. Why? Because it can be divided by 3. And according to the definition, the prime number cannot be divisible by any number other than 1 and the number itself. So, we will check if 9 is divisible by 2. No, it is not. Then we will divide by 3 and yes, it is divisible. So, 9 is not a prime number, according to our logic. Let’s check if 13 is a prime number. We will check if the number is divisible by 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, and 12. No, the number is not divisible by any of those numbers. We may also shorten our checking by only checking the number that is half of the number we are checking. Look at the following code: int primeChecker(int n) // n is our number which will be checked { int i; // Driver variable for the loop for (i = 2; i <= n / 2; i++) // Continued the loop till n/2 { if (n % i == 0) // If no reminder return 1; // It is not prime } return 0; // else it is prime } The code is quite simple. If the remainder is equal to zero, our number is fully divisible by a number other than 1 and itself, so it is not a prime number. If there is any remainder, the number is a prime number. Let’s write the full code and look at the output for the following numbers: 23 65 235 4,543 4,241 The full source code to check if the numbers are prime or not is as follows: void setup() { Serial.begin(9600); primeChecker(23); // We called our function passing our number to test. primeChecker(65); primeChecker(235); primeChecker(4543); primeChecker(4241); } void loop() { } int primeChecker(int n) { int i; //driver variable for the loop for (i = 2; i <= n / 2; ++i) //loop continued until the half of the numebr { if (n % i == 0) return Serial.println(“Not a prime number“); // returned the number status } return Serial.println(“A prime number“); } This is a very simple code. We just called our primeChecker() function and passed our numbers. Inside our primeChecker() function, we wrote the logic to check our number. Now let’s look at the output: From the output, we can see that, other than 23 and 4,241, none of the numbers are prime. Let’s look at an example, where we will write four functions: add(), sub(), mul(), and divi(). Into these functions, we will pass two numbers, and print the value on the serial monitor. The four functions can be defined as follows: float sum(float a, float b) { float sum = a + b; return sum; } float sub(float a, float b) { float sub = a - b; return sub; } float mul(float a, float b) { float mul = a * b; return mul; } float divi(float a, float b) { float divi = a / b; return divi; } Now write the rest of the code, which will give the following outputs: Usages of functions You may wonder which type of function we should use. The answer is simple. The usages of the functions are dependent on the operations of the programs. But whatever the function is, I would suggest to do only a single task with a function. Do not do multiple tasks inside a function. This will usually speed up your processing time and the calculation time of the code. You may also want to know why we even need to use functions. Well, there a number of uses of functions, as follows: Functions help programmers write more organized code Functions help to reduce errors by simplifying code Functions make the whole code smaller Functions create an opportunity to use the code multiple times Exercise To extend your knowledge of functions, you may want to do the following exercise: Write a program to check if a number is even or odd. (Hint: you may remember the % operator). Write a function that will find the largest number among four numbers. The numbers will be passed as arguments through the function. (Hint: use if-else conditions). Suppose you work in a garment factory. They need to know the area of a cloth. The area can be in float. They will provide you the length and height of the cloth. Now write a program using functions to find out the area of the cloth. (Use basic calculation in the user-defined function). Summary This article gave us a hint about the functions that Arduino perform. With this information we can create even more programs that is supportive in nature with Arduino. Resources for Article: Further resources on this subject: Connecting Arduino to the Web [article] Getting Started with Arduino [article] Arduino Development [article]
Read more
  • 0
  • 0
  • 38179

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
  • 38171
Modal Close icon
Modal Close icon