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-generating-automated-image-captions-using-nlp-and-computer-vision-tutorial
Melisha Dsouza
06 Jan 2019
18 min read
Save for later

Generating automated image captions using NLP and computer vision [Tutorial]

Melisha Dsouza
06 Jan 2019
18 min read
In this tutorial, we will combine techniques in both computer vision and natural language processing to form a complete image description approach. This will be responsible for constructing computer-generated natural descriptions of any provided images.  The idea is to replace the encoder (RNN layer) in an encoder-decoder architecture with a deep convolutional neural network (CNN) trained to classify objects in images. Normally, the CNN's last layer is the softmax layer, which assigns the probability that each object might be in the image. But if we remove that softmax layer from CNN, we can feed the CNN's rich encoding of the image into the decoder (language generation RNN) designed to produce phrases. We can then train the whole system directly on images and their captions, so it maximizes the likelihood that the descriptions it produces best match the training descriptions for each image. This tutorial is an excerpt from a book written by  Matthew Lamons, Rahul Kumar, Abhishek Nagaraja titled Python Deep Learning Projects. This book will simplify and ease how deep learning works, demonstrating how neural networks play a vital role in exploring predictive analytics across different domains. Users will explore projects in the field of computational linguistics, computer vision, machine translation, pattern recognition and many more! All of the Python files and Jupyter Notebook files for this tutorial can be found at GitHub. In this implementation, we will be using a pretrained Inception-v3 model as a feature extractor in an encoder trained on the ImageNet dataset. Let's import all of the dependencies that we will need to build an auto-captioning model. All of the Python files and the Jupyter Notebooks for this article can be found on GitHub. Initialization For this implementation, we need a TensorFlow version greater than or equal to 1.9 and we will also enable the eager execution mode, which will help us use the debug the code more effectively. Here is the code for this: # Import TensorFlow and enable eager execution import tensorflow as tf tf.enable_eager_execution() import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from sklearn.utils import shuffle import re import numpy as np import os import time import json from glob import glob from PIL import Image import pickle Download and prepare the MS-COCO dataset We are going to use the MS-COCO dataset to train our model. This dataset contains more than 82,000 images, each of which has been annotated with at least five different captions. The following code will download and extract the dataset automatically: annotation_zip = tf.keras.utils.get_file('captions.zip', cache_subdir=os.path.abspath('.'), origin = 'http://images.cocodataset.org/annotations/annotations_trainval2014.zip', extract = True) annotation_file = os.path.dirname(annotation_zip)+'/annotations/captions_train2014.json' name_of_zip = 'train2014.zip' if not os.path.exists(os.path.abspath('.') + '/' + name_of_zip): image_zip = tf.keras.utils.get_file(name_of_zip, cache_subdir=os.path.abspath('.'), origin = 'http://images.cocodataset.org/zips/train2014.zip', extract = True) PATH = os.path.dirname(image_zip)+'/train2014/' else: PATH = os.path.abspath('.')+'/train2014/' The following will be the output: Downloading data from http://images.cocodataset.org/annotations/annotations_trainval2014.zip 252878848/252872794 [==============================] - 6s 0us/step Downloading data from http://images.cocodataset.org/zips/train2014.zip 13510574080/13510573713 [==============================] - 322s 0us/step For this example, we'll select a subset of 40,000 captions and use these and the corresponding images to train our model. As always, captioning quality will improve if you choose to use more data: # read the json annotation file with open(annotation_file, 'r') as f: annotations = json.load(f) # storing the captions and the image name in vectors all_captions = [] all_img_name_vector = [] for annot in annotations['annotations']: caption = '<start> ' + annot['caption'] + ' <end>' image_id = annot['image_id'] full_coco_image_path = PATH + 'COCO_train2014_' + '%012d.jpg' % (image_id) all_img_name_vector.append(full_coco_image_path) all_captions.append(caption) # shuffling the captions and image_names together # setting a random state train_captions, img_name_vector = shuffle(all_captions, all_img_name_vector, random_state=1) # selecting the first 40000 captions from the shuffled set num_examples = 40000 train_captions = train_captions[:num_examples] img_name_vector = img_name_vector[:num_examples] Once the data preparation is completed, we will have all of the image path stored in the img_name_vector list variable, and the associated captions are stored in train_caption, as shown in the following screenshot: Data preparation for a deep CNN encoder Next, we will use Inception-v3 (pretrained on ImageNet) to classify each image. We will extract features from the last convolutional layer. We will create a helper function that will transform the input image to the format that is expected by Inception-v3: #Resizing the image to (299, 299) #Using the preprocess_input method to place the pixels in the range of -1 to 1. def load_image(image_path): img = tf.read_file(image_path) img = tf.image.decode_jpeg(img, channels=3) img = tf.image.resize_images(img, (299, 299)) img = tf.keras.applications.inception_v3.preprocess_input(img) return img, image_path Now let's initialize the Inception-v3 model and load the pretrained ImageNet weights. To do so, we'll create a tf.keras model where the output layer is the last convolutional layer in the Inception-v3 architecture. image_model = tf.keras.applications.InceptionV3(include_top=False, weights='imagenet') new_input = image_model.input hidden_layer = image_model.layers[-1].output image_features_extract_model = tf.keras.Model(new_input, hidden_layer) The output is as follows: Downloading data from https://github.com/fchollet/deep-learning-models/releases/download/v0.5/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5 87916544/87910968 [==============================] - 40s 0us/step So, the image_features_extract_model is our deep CNN encoder, which is responsible for learning the features from the given image. Performing feature extraction Now we will pre-process each image with the deep CNN encoder and dump the output to the disk: We will load the images in batches using the load_image() helper function that we created before We will feed the images into the encoder to extract the features Dump the features as a numpy array: encode_train = sorted(set(img_name_vector)) #Load images image_dataset = tf.data.Dataset.from_tensor_slices( encode_train).map(load_image).batch(16) # Extract features for img, path in image_dataset: batch_features = image_features_extract_model(img) batch_features = tf.reshape(batch_features, (batch_features.shape[0], -1, batch_features.shape[3])) #Dump into disk for bf, p in zip(batch_features, path): path_of_feature = p.numpy().decode("utf-8") np.save(path_of_feature, bf.numpy()) Data prep for a language generation (RNN) decoder The first step is to pre-process the captions. We will perform a few basic pre-processing steps on the captions, such as the following: We'll tokenize the captions (for example, by splitting on spaces). This will help us to build a vocabulary of all the unique words in the data (for example, "playing", "football", and so on). We'll limit the vocabulary size to the top 5,000 words to save memory. We'll replace all other words with the token unk (for unknown). You can obviously optimize that according to the use case. We will then create a word --> index mapping and vice versa. We will finally pad all sequences to be the same length as the longest one. Here is the code for that: # Helper func to find the maximum length of any caption in our dataset def calc_max_length(tensor): return max(len(t) for t in tensor) # Performing tokenization on the top 5000 words from the vocabulary top_k = 5000 tokenizer = tf.keras.preprocessing.text.Tokenizer(num_words=top_k, oov_token="<unk>", filters='!"#$%&()*+.,-/:;=?@[\]^_`{|}~ ') # Converting text into sequence of numbers tokenizer.fit_on_texts(train_captions) train_seqs = tokenizer.texts_to_sequences(train_captions) tokenizer.word_index = {key:value for key, value in tokenizer.word_index.items() if value <= top_k} # putting <unk> token in the word2idx dictionary tokenizer.word_index[tokenizer.oov_token] = top_k + 1 tokenizer.word_index['<pad>'] = 0 # creating the tokenized vectors train_seqs = tokenizer.texts_to_sequences(train_captions) # creating a reverse mapping (index -> word) index_word = {value:key for key, value in tokenizer.word_index.items()} # padding each vector to the max_length of the captions cap_vector = tf.keras.preprocessing.sequence.pad_sequences(train_seqs, padding='post') # calculating the max_length # used to store the attention weights max_length = calc_max_length(train_seqs) The end result will be an array of a sequence of integers: We will split the data into training and validation samples using an 80:20 split ratio: img_name_train, img_name_val, cap_train, cap_val = train_test_split(img_name_vector,cap_vector,test_size=0.2,random_state=0) # Checking the sample counts print ("No of Training Images:",len(img_name_train)) print ("No of Training Caption: ",len(cap_train) ) print ("No of Training Images",len(img_name_val)) print ("No of Training Caption:",len(cap_val) ) No of Training Images: 24000 No of Training Caption: 24000 No of Training Images 6000 No of Training Caption: 6000 Setting up the data pipeline Our images and captions are ready! Next, let's create a tf.data dataset to use for training our model. Now we will prepare the pipeline for an image and the text model by performing transformations and batching on them: # Defining parameters BATCH_SIZE = 64 BUFFER_SIZE = 1000 embedding_dim = 256 units = 512 vocab_size = len(tokenizer.word_index) # shape of the vector extracted from Inception-V3 is (64, 2048) # these two variables represent that features_shape = 2048 attention_features_shape = 64 # loading the numpy files def map_func(img_name, cap): img_tensor = np.load(img_name.decode('utf-8')+'.npy') return img_tensor, cap #We use the from_tensor_slices to load the raw data and transform them into the tensors dataset = tf.data.Dataset.from_tensor_slices((img_name_train, cap_train)) # Using the map() to load the numpy files in parallel # NOTE: Make sure to set num_parallel_calls to the number of CPU cores you have # https://www.tensorflow.org/api_docs/python/tf/py_func dataset = dataset.map(lambda item1, item2: tf.py_func( map_func, [item1, item2], [tf.float32, tf.int32]), num_parallel_calls=8) # shuffling and batching dataset = dataset.shuffle(BUFFER_SIZE) dataset = dataset.batch(BATCH_SIZE) dataset = dataset.prefetch(1) Defining the captioning model The model architecture we are using to build the auto captioning is inspired by the Show, Attend and Tell paper. The features that we extracted from the lower convolutional layer of Inception-v3 gave us a vector of a shape of (8, 8, 2048). Then, we squash that to a shape of (64, 2048). This vector is then passed through the CNN encoder, which consists of a single fully connected layer. The RNN (GRU in our case) attends over the image to predict the next word: def gru(units): if tf.test.is_gpu_available(): return tf.keras.layers.CuDNNGRU(units, return_sequences=True, return_state=True, recurrent_initializer='glorot_uniform') else: return tf.keras.layers.GRU(units, return_sequences=True, return_state=True, recurrent_activation='sigmoid', recurrent_initializer='glorot_uniform') Attention Now we will define the attention mechanism popularly known as Bahdanau attention. We will need the features from the CNN encoder of a shape of (batch_size, 64, embedding_dim). This attention mechanism will return the context vector and the attention weights over the time axis: class BahdanauAttention(tf.keras.Model): def __init__(self, units): super(BahdanauAttention, self).__init__() self.W1 = tf.keras.layers.Dense(units) self.W2 = tf.keras.layers.Dense(units) self.V = tf.keras.layers.Dense(1) def call(self, features, hidden): # hidden_with_time_axis shape == (batch_size, 1, hidden_size) hidden_with_time_axis = tf.expand_dims(hidden, 1) # score shape == (batch_size, 64, hidden_size) score = tf.nn.tanh(self.W1(features) + self.W2(hidden_with_time_axis)) # attention_weights shape == (batch_size, 64, 1) # we get 1 at the last axis because we are applying score to self.V attention_weights = tf.nn.softmax(self.V(score), axis=1) # context_vector shape after sum == (batch_size, hidden_size) context_vector = attention_weights * features context_vector = tf.reduce_sum(context_vector, axis=1) return context_vector, attention_weights You can refer to the book to understand the CNN encoder, RNN decoder and Loss function used. Training the captioning model Let's the model. The first thing we need to do is to extract the features stored in the respective .npy files and then pass those features through the CNN encoder. The encoder output, hidden state (initialized to 0) and the decoder input (which is the start token) are passed to the decoder. The decoder returns the predictions and the decoder hidden state. The decoder hidden state is then passed back into the model and the predictions are used to calculate the loss. While training, we use the teacher forcing technique to decide the next input to the decoder. The final step is to calculate the gradient and apply it to the optimizer and backpropagate: EPOCHS = 20 loss_plot = [] for epoch in range(EPOCHS): start = time.time() total_loss = 0 for (batch, (img_tensor, target)) in enumerate(dataset): loss = 0 # initializing the hidden state for each batch # because the captions are not related from image to image hidden = decoder.reset_state(batch_size=target.shape[0]) dec_input = tf.expand_dims([tokenizer.word_index['<start>']] * BATCH_SIZE, 1) with tf.GradientTape() as tape: features = encoder(img_tensor) for i in range(1, target.shape[1]): # passing the features through the decoder predictions, hidden, _ = decoder(dec_input, features, hidden) loss += loss_function(target[:, i], predictions) # using teacher forcing dec_input = tf.expand_dims(target[:, i], 1) total_loss += (loss / int(target.shape[1])) variables = encoder.variables + decoder.variables gradients = tape.gradient(loss, variables) optimizer.apply_gradients(zip(gradients, variables), tf.train.get_or_create_global_step()) if batch % 100 == 0: print ('Epoch {} Batch {} Loss {:.4f}'.format(epoch + 1, batch, loss.numpy() / int(target.shape[1]))) # storing the epoch end loss value to plot later loss_plot.append(total_loss / len(cap_vector)) print ('Epoch {} Loss {:.6f}'.format(epoch + 1, total_loss/len(cap_vector))) print ('Time taken for 1 epoch {} sec\n'.format(time.time() - start)) The following is the output: After performing the training process over few epochs lets plot the Epoch vs Loss graph: plt.plot(loss_plot) plt.xlabel('Epochs') plt.ylabel('Loss') plt.title('Loss Plot') plt.show() The output is as follows: The loss vs Epoch plot during training process Evaluating the captioning model The evaluation function is similar to the training loop, except we don't use teacher forcing here. The input to the decoder at each time step is its previous predictions, along with the hidden state and the encoder output. A few key points to remember while making predictions: Stop predicting when the model predicts the end token Store the attention weights for every time step Let’s define the evaluate() function: def evaluate(image): attention_plot = np.zeros((max_length, attention_features_shape)) hidden = decoder.reset_state(batch_size=1) temp_input = tf.expand_dims(load_image(image)[0], 0) img_tensor_val = image_features_extract_model(temp_input) img_tensor_val = tf.reshape(img_tensor_val, (img_tensor_val.shape[0], -1, img_tensor_val.shape[3])) features = encoder(img_tensor_val) dec_input = tf.expand_dims([tokenizer.word_index['<start>']], 0) result = [] for i in range(max_length): predictions, hidden, attention_weights = decoder(dec_input, features, hidden) attention_plot[i] = tf.reshape(attention_weights, (-1, )).numpy() predicted_id = tf.argmax(predictions[0]).numpy() result.append(index_word[predicted_id]) if index_word[predicted_id] == '<end>': return result, attention_plot dec_input = tf.expand_dims([predicted_id], 0) attention_plot = attention_plot[:len(result), :] return result, attention_plot Also, let's create a helper function to visualize the attention points that predict the words: def plot_attention(image, result, attention_plot): temp_image = np.array(Image.open(image)) fig = plt.figure(figsize=(10, 10)) len_result = len(result) for l in range(len_result): temp_att = np.resize(attention_plot[l], (8, 8)) ax = fig.add_subplot(len_result//2, len_result//2, l+1) ax.set_title(result[l]) img = ax.imshow(temp_image) ax.imshow(temp_att, cmap='gray', alpha=0.6, extent=img.get_extent()) plt.tight_layout() plt.show() # captions on the validation set rid = np.random.randint(0, len(img_name_val)) image = img_name_val[rid] real_caption = ' '.join([index_word[i] for i in cap_val[rid] if i not in [0]]) result, attention_plot = evaluate(image) print ('Real Caption:', real_caption) print ('Prediction Caption:', ' '.join(result)) plot_attention(image, result, attention_plot) # opening the image Image.open(img_name_val[rid]) The output is as follows: Deploying the captioning model We will deploy the complete module as a RESTful service. To do so, we will write an inference code that loads the latest checkpoint and makes the prediction on the given image. Look into the inference.py file in the repository. All the code is similar to the training loop except we don't use teacher forcing here. The input to the decoder at each time step is its previous predictions, along with the hidden state and the encoder output. One important part is to load the model in memory for which we are using the tf.train.Checkpoint() method, which loads all of the learned weights for optimizer, encoder, decoder into the memory. Here is the code for that: checkpoint_dir = './my_model' checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt") checkpoint = tf.train.Checkpoint( optimizer=optimizer, encoder=encoder, decoder=decoder, ) checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir)) So, we will create an evaluate() function, which defines the prediction loop. To make sure that the prediction ends after certain words, we will stop predicting when the model predicts the end token, <end>: def evaluate(image): attention_plot = np.zeros((max_length, attention_features_shape)) hidden = decoder.reset_state(batch_size=1) temp_input = tf.expand_dims(load_image(image)[0], 0) # Extract features from the test image img_tensor_val = image_features_extract_model(temp_input) img_tensor_val = tf.reshape(img_tensor_val, (img_tensor_val.shape[0], -1, img_tensor_val.shape[3])) # Feature is fed into the encoder features = encoder(img_tensor_val) dec_input = tf.expand_dims([tokenizer.word_index['<start>']], 0) result = [] # Prediction loop for i in range(max_length): predictions, hidden, attention_weights = decoder(dec_input, features, hidden) attention_plot[i] = tf.reshape(attention_weights, (-1, )).numpy() predicted_id = tf.argmax(predictions[0]).numpy() result.append(index_word[predicted_id]) # Hard stop when end token is predicted if index_word[predicted_id] == '<end>': return result, attention_plot dec_input = tf.expand_dims([predicted_id], 0) attention_plot = attention_plot[:len(result), :] return result, attention_plot Now let's use this evaluate() function in our web application code: #!/usr/bin/env python2 # -*- coding: utf-8 -*- """ @author: rahulkumar """ from flask import Flask , request, jsonify import time from inference import evaluate import tensorflow as tf app = Flask(__name__) @app.route("/wowme") def AutoImageCaption(): image_url=request.args.get('image') print('image_url') image_extension = image_url[-4:] image_path = tf.keras.utils.get_file(str(int(time.time()))+image_extension, origin=image_url) result, attention_plot = evaluate(image_path) data = {'Prediction Caption:': ' '.join(result)} return jsonify(data) if __name__ == "__main__": app.run(host = '0.0.0.0',port=8081) Execute the following command in the Terminal to run the web app: python caption_deploy_api.py You should get the following output: * Running on http://0.0.0.0:8081/ (Press CTRL+C to quit) Now we request the API, as follows: curl 0.0.0.0:8081/wowme?image=https://www.beautifulpeopleibiza.com/images/BPI/img_bpi_destacada.jpg We should get our caption predicted, as shown in the following screenshot: Make sure to train the model on the large image to get better predictions. Summary In this implementation, we used a pre trained Inception-v3 model as a feature extractor in an encoder trained on the ImageNet dataset as part of a deep learning solution. This solution combines techniques in both computer vision and natural language processing, to form a complete image description approach, able to construct computer-generated natural descriptions of any provided images. We've broken the barrier between images and language with this trained model and we've provided a technology that could be used as part of an application, helping the visually impaired enjoy the benefits of the megatrend of photo sharing! To understand insightful projects to master deep learning and neural network architectures using Python and Keras, check out our book  Python Deep Learning Projects. Getting started with Web Scraping using Python [Tutorial] Google researchers introduce JAX: A TensorFlow-like framework for generating high-performance code from Python and NumPy machine learning programs Google releases Magenta studio beta, an open source python machine learning library for music artists
Read more
  • 0
  • 0
  • 34073

article-image-4-predictions-by-richard-feldman-on-the-future-of-the-web-typescript-webassembly-and-more
Bhagyashree R
26 Nov 2019
8 min read
Save for later

4 predictions by Richard Feldman on the future of the web: TypeScript, WebAssembly, and more

Bhagyashree R
26 Nov 2019
8 min read
At ReactiveConf 2019, Richard Feldman, author of Elm in Action and creator of ‘elm-css’ made four predictions about how the future of web development will look like by the end of 2020 and 2025. ReactiveConf 2019 was a three-day functional programming event that happened from October 30 to November 1 at Prague. The event hosted a number of great talks sharing the latest global trends in web and mobile development. This year among the topics covered were PWA, optimizations, security, visualizations, accessibility, and diversity. Predicting the future of the web is about safer bets than about trends Feldman started out by asking a question that developers often come across: “which technology stack to choose for their next project?” Previously, it was often advised to go for technologies that are “boring” or mature instead of the latest and shiniest ones. Going by this advice Feldman and his team chose the technology that had the biggest library ecosystem, most mature in the LAMP stack, and was adopted by many successful companies: Perl. Since then, however, Perl gradually started to lose its popularity. The lesson that Feldman learned here was that “any technology that we choose, no matter how popular, how mainstream, how much traction it got today, you are still making a bet.” He says that predicting how the future for the current technologies will look like, and following that is safer than blindly accepting what everyone else is doing. After setting up the premise, Feldman moved on to sharing his predictions: Prediction 1: "TypeScript takes over the JS world" Back in 2012, Anders Hejlsberg, who is the original designer of C#, Delphi, and Turbo Pascal, came up with another programming language called TypeScript. This language was introduced as a “superset” of JavaScript that will help developers build JavaScript apps that scale. Some of the positives that this language brought to JavaScript development was excellent tooling enabled by static typing, self-documentation of code, continuous feedback from autocomplete, and more. Since its introduction, TypeScript has seen huge adoption. Almost all the big frontend frameworks such as React, Angular and Vue have extensive Typescript support. More and more JavaScript developers and framework authors are taking advantage of the excellent tooling and other benefits it provides. Its latest release, TypeScript 3.7 includes most-awaited features like assert signatures, recursive type aliases, top-level await, null coalescing, and optional chaining. [box type="shadow" align="" class="" width=""] Further Learning If you are interested in building with TypeScript and its latest features, check out our book, Learn TypeScript 3 by Building Web Applications by Sebastien Dubois and Alexis Georges. This book covers the very basics to the more advanced concepts while explaining many design patterns, techniques, frameworks, libraries, and tools along the way. You will learn a ton about modern web frameworks like Angular, Vue.js and React, and build cool web applications using those. It also covers modern front-end development tooling such as Node.js, npm, yarn, Webpack, Parcel, Jest, and many others. [/box] Despite its popularity, not everyone is using TypeScript. Along with verbose code, it is “unsound” by design and gives a false sense of security in some instances, Feldman shared. So, there are people who like TypeScript and there are people who don’t. The most important factor to predict how its future will look like is by seeing how it is affecting the teams actually using it. Feldman said, "I hear a lot of teams saying we are trying Typescript, we have used Typescript, or we are using TypeScript. I hear almost no teams saying we tried Typescript and then went back to JavaScript." [box type="shadow" align="" class="" width=""] Feldman predicted that by the end of 2020, Typescript will be the most common choice for new JS commercial projects. And by the end of 2025, he predicted that there will be more people writing in TypeScript on a daily basis than people writing vanilla JavaScript. [/box] Prediction 2: “WebAssembly is going to expand the web app pie” First announced in 2015, WebAssembly is Assembly for the browser with a compact binary format that runs with near-native execution speed. It is also a compilation target for other high-level languages including C/C++ and Rust. Its “closer to metal” property enables a number of computationally-intensive use cases on the web including games, media editing, speech synthesis, client-side computer vision, among others. Start your WebAssembly journey with our book Hands-On Game Development with WebAssembly by Rick Battagline. This book introduces web and game devs to the world of WebAssembly by walking through the development of a retro arcade game. WebAssembly is designed to work alongside JavaScript, which means you can call WebAssembly modules from JavaScript code. Though it can be used to improve the performance of JavaScript apps and libraries, Feldman doubts that this will be the only major way developers are going to use it in the future. This is because the existing performance of JavaScript is generally accepted and promising some percentage of improvement in speed is not going to be a game-changer for WebAssembly. Instead, Feldman believes that WebAssmebly will enable browsers to compete with apps stores and installers. Getting users to install an app can be a significant obstacle to adoption. WebAssembly can help distribute native code without code signing, app stores, and development kits. Also, the web as a delivery platform provides deep linking and other sharing capabilities. He explained this through the example of Figma, a collaborative interface design tool built in C++, which users can access just going to a URL. However, distributing applications built in Rust, C++, or Go on web does not mean the end of HTML, CSS, and JavaScript. WebAssembly will simply expand what he calls as the “web app pie.” [box type="shadow" align="" class="" width=""]Feldman predicted that by the end of 2020, WebAssembly will not make much difference to the makeup of the web. By the end of 2025, however, we will start to see the niche of heavyweight web apps that are basically native apps distributed through the browser.[/box] Prediction 3: “npm lasts, surviving further problems” In recent years, developers have witnessed and survived quite a few npm disasters. In 2016, a developer unpublished more than 250 npm-managed modules that affected Node, Babel and thousands of other projects. Then in 2018, we saw the event-stream case, in which an ill-intentioned user took ownership of the widely-used package through social engineering and infected it with a malicious package. Another problem with npm is that it can allow the execution of arbitrary code from thousands and thousands of packages through the “postinstall” hook in package.json. Feldman recommends disabling “postinstall” and “preinstall” scripts by using the following command: npm config set ignore-scripts true Also, we are seeing some alternatives to npm. Feldman mentioned about Entropic, a federated package registry with a new CLI introduced by the former CTO of npm, C J Silverio. Feldman believes that despite these alternatives, financial, security, or other problems developers will continue to use npm because of its strong network effects. [box type="shadow" align="" class="" width=""]Drawing from these events, Feldman predicted that by the end of 2020, we can expect one more security incident. By the end of 2025, he predicts that we might see at least one malicious npm package infecting many developers’ machines.[/box] Prediction 4: "JS alternatives stay niche, but age well" When it comes to JavaScript alternatives, we have two options: JS dialects and non-JS dialects. Some of the JS dialects are TypeScript, Dart, Coffeescript, among others. Whereas, non-JS dialects include ClojureScript, ReasonML, and Elm, which provide a different experience than writing JavaScript. Representing the Elm core team at the event, Feldman listed a few reasons why developers should try Elm. It renders faster and generates smaller builds than most top JS frameworks and almost never crashes. It has its own package ecosystem and is often praised for its very detailed error messages. After sharing the benefits of Elm, Feldman concluded that JavaScript alternatives will stay niche, but age well. This essentially means that people who have chosen these alternatives and are happy with them will continue to use them regardless of the popularity of TypeScript. [box type="shadow" align="" class="" width=""]By the end of 2020, compile-to-JS languages will continue to grow, but not as fast as TypeScript. By the end of 2025, non-JavaScript dialects will have aged well, although at that time TypeScript will still be more popular.[/box] Want to add TypeScript to your skillset? Check out our book, Learn TypeScript 3 by Building Web Applications by Sebastien Dubois and Alexis Georges. It is a comprehensive guide that teaches how to wisely use the latest features in TypeScript 3.  You will learn how to build web applications with Angular, Vue.js and React and use modern front-end development tooling such as Node.js, npm, yarn, Webpack, Parcel, Jest, and many others. Microsoft releases TypeScript 3.7 with much-awaited features like Optional Chaining, Assertion functions and more Microsoft introduces Static TypeScript, as an alternative to embedded interpreters, for programming MCU-based devices An introduction to TypeScript types for ASP.NET core [Tutorial]
Read more
  • 0
  • 0
  • 34024

article-image-create-aws-cloudtrail
Vijin Boricha
09 May 2018
8 min read
Save for later

How to create your own AWS CloudTrail

Vijin Boricha
09 May 2018
8 min read
AWS provides a wide variety of tools and managed services which allow you to safeguard your applications running on the cloud, such as AWS WAF and AWS Shield. But this, however, just forms one important piece of a much larger jigsaw puzzle! What about compliance monitoring, risk auditing, and overall governance of your environments? How do you effectively analyze events occurring in your environment and mitigate against the same? Well, luckily for us, AWS has the answer to our problems in the form of AWS CloudTrail. In today's post, we will explore AWS CloudTrail and learn how to create our own CloudTrail trail. [box type="shadow" align="" class="" width=""]This tutorial is an excerpt from the book AWS Administration - The Definitive Guide - Second Edition, written by Yohan Wadia.  This book will help you create a highly secure, fault-tolerant, and scalable Cloud environment for your applications to run on.[/box] AWS CloudTrail provides you with the ability to log every single action taken by a user, service, role, or even API, from within your AWS account. Each action recorded is treated as an event which can then be analyzed for enhancing the security of your AWS environment. The following are some of the key benefits that you can obtain by enabling CloudTrail for your AWS accounts: In-depth visibility: Using CloudTrail, you can easily gain better insights into your account's usage by recording each user's activities, such as which user initiated a new resource creation, from which IP address was this request initiated, which resources were created and at what time, and much more! Easier compliance monitoring: With CloudTrail, you can easily record and log events occurring within your AWS account, whether they may originate from the Management Console, or the AWS CLI, or even from other AWS tools and services. The best thing about this is that you can integrate CloudTrail with another AWS service, such as Amazon CloudWatch, to alert and respond to out-of-compliance events. Security automations: Automating responses to security threats not only enables you to mitigate the potential threats faster, but also provides you with a mechanism to stop all further attacks. The same can be applied to AWS CloudTrail as well! With its easy integration with Amazon CloudWatch events, you can now create corresponding Lambda functions that trigger automatically each time a compliance is not met, all in a matter of seconds! CloudTrail's essential concepts and terminologies With these key points in mind, let's have a quick look at some of CloudTrail's essential concepts and terminologies: Events Events are the basic unit of measurement in CloudTrail. Essentially, an event is nothing more than a record of a particular activity either initiated by the AWS services, roles, or even an AWS user. These activities are all logged as API calls that can originate from the Management Console, the AWS SDK, or even the AWS CLI as well. By default, events are stored by CloudTrail with S3 buckets for a period of 7 days. You can view, search, and even download these events by leveraging the events history feature provided by CloudTrail. Trails Trails are essentially the delivery mechanism, using which events are dumped to S3 buckets. You can use these trails to log specific events within specific buckets, as well as to filter events and encrypt the transmitted log files. By default, you can have a maximum of five trails created per AWS region, and this limit cannot by increased. CloudTrail Logs Once your CloudTrail starts capturing events, it sends these events to an S3 bucket in the form of a CloudTrail Log file. The log files are JSON text files that are compressed using the .gzip format. Each file can contain one or more events within itself. Here is a simple representation of what a CloudTrail Log looks like. In this case, the event was created when I tried to add an existing user by the name of Mike to an administrator group using the AWS Management Console: {"Records": [{ "eventVersion": "1.0", "userIdentity": { "type": "IAMUser", "principalId": "12345678", "arn": "arn:aws:iam::012345678910:user/yohan", "accountId": "012345678910", "accessKeyId": "AA34FG67GH89", "userName": "Alice", "sessionContext": {"attributes": { "mfaAuthenticated": "false", "creationDate": "2017-11-08T13:01:44Z" }} }, "eventTime": "2017-11-08T13:09:44Z", "eventSource": "iam.amazonaws.com", "eventName": "AddUserToGroup", "awsRegion": "us-east-1", "sourceIPAddress": "127.0.0.1", "userAgent": "AWSConsole", "requestParameters": { "userName": "Mike", "groupName": "administrator" }, "responseElements": null }]} You can view your own CloudTrail Log files by visiting the S3 bucket that you specify during the trail's creation. Each log file is named uniquely using the following format: AccountID_CloudTrail_RegionName_YYYYMMDDTHHmmZ_UniqueString.json.gz Where: AccountID: Your AWS account ID. RegionName: AWS region where the event was captured: us-east-1, and so on. YYYYMMDDTTHHmmz: Specifies the year, month, day, hour (24 hours), minutes, and seconds. The z indicates time in UTC. UniqueString: A randomly generated 16-character-long string that is simply used so that there is no overwriting of the log files. With the basics in mind, let's quickly have a look at how you can get started with CloudTrail for your own AWS environments! Creating your first CloudTrail Trail To get started, log in to your AWS Management Console and filter the CloudTrail service from the AWS services filter. On the CloudTrail dashboard, select the Create Trail option to get started: This will bring up the Create Trail wizard. Using this wizard, you can create a maximum of five-trails per region. Type a suitable name for the Trail into the Trail name field, to begin with. Next, you can either opt to Apply trail to all regions or only to the region out of which you are currently operating. Selecting all regions enables CloudTrail to record events from each region and dump the corresponding log files into an S3 bucket that you specify. Alternatively, selecting to record out of one region will only capture the events that occur from the region out of which you are currently operating. In my case, I have opted to enable the Trail only for the region I'm currently working out of. In the subsequent sections, we will learn how to change this value using the AWS CLI: Next, in the Management events section, select the type of events you wish to capture from your AWS environment. By default, CloudTrail records all management events that occur within your AWS account. These events can be API operations, such as events caused due to the invocation of an EC2 RunInstances or TerminateInstances operation, or even non-API based events, such as a user logging into the AWS Management Console, and so on. For this particular use case, I've opted to record All management events. Selecting the Read-only option will capture all the GET API operations, whereas the Write-only option will capture only the PUT API operations that occur within your AWS environment. Moving on, in the Storage location section, provide a suitable name for the S3 bucket that will store your CloudTrail Log files. This bucket will store all your CloudTrail Log files, irrespective of the regions the logs originated from. You can alternatively select an existing bucket from the S3 bucket selection field: Next, from the Advanced section, you can optionally configure a Log file prefix. By default, the logs will automatically get stored under a folder-like hierarchy that is usually of the form AWSLogs/ACCOUNT_ID/CloudTrail/REGION. You can also opt to Encrypt log files with the help of an AWS KMS key. Enabling this feature is highly recommended for production use. Selecting Yes in the Enable log file validation field enables you to verify the integrity of the delivered log files once they are delivered to the S3 bucket. Finally, you can even enable CloudTrail to send you notifications each time a new log file is delivered to your S3 bucket by selecting Yes against the Send SNS notification for every log file delivery option. This will provide you with an additional option to either select a predefined SNS topic or alternatively create a new one specifically for this particular CloudTrail. Once all the required fields are filled in, click on Create to continue. With this, you should be able to see the newly created Trail by selecting the Trails option from the CloudTrail dashboard's navigation pane, as shown in the following screenshot: We learned to create a new trail and enable notifications each time a new log file is delivered. If you are interested to learn more about CloudTrail Logs and AWS Config you may refer to this book  AWS Administration - The Definitive Guide - Second Edition. AWS SAM (AWS Serverless Application Model) is now open source! How to run Lambda functions on AWS Greengrass AWS Greengrass brings machine learning to the edge
Read more
  • 0
  • 0
  • 34021

article-image-jupyter-and-python-scripting
Packt
21 Oct 2016
9 min read
Save for later

Jupyter and Python Scripting

Packt
21 Oct 2016
9 min read
In this article by Dan Toomey, author of the book Learning Jupyter, we will see data access in Jupyter with Python and the effect of pandas on Jupyter. We will also see Python graphics and lastly Python random numbers. (For more resources related to this topic, see here.) Python data access in Jupyter I started a view for pandas using Python Data Access as the name. We will read in a large dataset and compute some standard statistics on the data. We are interested in seeing how we use pandas in Jupyter, how well the script performs, and what information is stored in the metadata (especially if it is a larger dataset). Our script accesses the iris dataset built into one of the Python packages. All we are looking to do is read in a slightly large number of items and calculate some basic operations on the dataset. We are really interested in seeing how much of the data is cached in the PYNB file. The Python code is: # import the datasets package from sklearn import datasets # pull in the iris data iris_dataset = datasets.load_iris() # grab the first two columns of data X = iris_dataset.data[:, :2] # calculate some basic statistics x_count = len(X.flat) x_min = X[:, 0].min() - .5 x_max = X[:, 0].max() + .5 x_mean = X[:, 0].mean() # display our results x_count, x_min, x_max, x_mean I broke these steps into a couple of cells in Jupyter, as shown in the following screenshot: Now, run the cells (using Cell | Run All) and you get this display below. The only difference is the last Out line where our values are displayed. It seemed to take longer to load the library (the first time I ran the script) than to read the data and calculate the statistics. If we look in the PYNB file for this notebook, we see that none of the data is cached in the PYNB file. We simply have code references to the library, our code, and the output from when we last calculated the script: { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(300, 3.7999999999999998, 8.4000000000000004, 5.8433333333333337)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# calculate some basic statisticsn", "x_count = len(X.flat)n", "x_min = X[:, 0].min() - .5n", "x_max = X[:, 0].max() + .5n", "x_mean = X[:, 0].mean()n", "n", "# display our resultsn", "x_count, x_min, x_max, x_mean" ] } Python pandas in Jupyter One of the most widely used features of Python is pandas. pandas are built-in libraries of data analysis packages that can be used freely. In this example, we will develop a Python script that uses pandas to see if there is any effect to using them in Jupyter. I am using the Titanic dataset from http://www.kaggle.com/c/titanic-gettingStarted/download/train.csv. I am sure the same data is available from a variety of sources. Here is our Python script that we want to run in Jupyter: from pandas import * training_set = read_csv('train.csv') training_set.head() male = training_set[training_set.sex == 'male'] female = training_set[training_set.sex =='female'] womens_survival_rate = float(sum(female.survived))/len(female) mens_survival_rate = float(sum(male.survived))/len(male) The result is… we calculate the survival rates of the passengers based on sex. We create a new notebook, enter the script into appropriate cells, include adding displays of calculated data at each point and produce our results. Here is our notebook laid out where we added displays of calculated data at each cell,as shown in the following screenshot: When I ran this script, I had two problems: On Windows, it is common to use backslash ("") to separate parts of a filename. However, this coding uses the backslash as a special character. So, I had to change over to use forward slash ("/") in my CSV file path. I originally had a full path to the CSV in the above code example. The dataset column names are taken directly from the file and are case sensitive. In this case, I was originally using the 'sex' field in my script, but in the CSV file the column is named Sex. Similarly I had to change survived to Survived. The final script and result looks like the following screenshot when we run it: I have used the head() function to display the first few lines of the dataset. It is interesting… the amount of detail that is available for all of the passengers. If you scroll down, you see the results as shown in the following screenshot: We see that 74% of the survivors were women versus just 19% men. I would like to think chivalry is not dead! Curiously the results do not total to 100%. However, like every other dataset I have seen, there is missing and/or inaccurate data present. Python graphics in Jupyter How do Python graphics work in Jupyter? I started another view for this named Python Graphics so as to distinguish the work. If we were to build a sample dataset of baby names and the number of births in a year of that name, we could then plot the data. The Python coding is simple: import pandas import matplotlib %matplotlib inline baby_name = ['Alice','Charles','Diane','Edward'] number_births = [96, 155, 66, 272] dataset = list(zip(baby_name,number_births)) df = pandas.DataFrame(data = dataset, columns=['Name', 'Number']) df['Number'].plot() The steps of the script are as follows: We import the graphics library (and data library) that we need Define our data Convert the data into a format that allows for easy graphical display Plot the data We would expect a resultant graph of the number of births by baby name. Taking the above script and placing it into cells of our Jupyter node, we get something that looks like the following screenshot: I have broken the script into different cells for easier readability. Having different cells also allows you to develop the script easily step by step, where you can display the values computed so far to validate your results. I have done this in most of the cells by displaying the dataset and DataFrame at the bottom of those cells. When we run this script (Cell | Run All), we see the results at each step displayed as the script progresses: And finally we see our plot of the births as shown in the following screenshot. I was curious what metadata was stored for this script. Looking into the IPYNB file, you can see the expected value for the formula cells. The tabular data display of the DataFrame is stored as HTML—convenient: { "cell_type": "code", "execution_count": 43, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "<div>n", "<table border="1" class="dataframe">n", "<thead>n", "<tr style="text-align: right;">n", "<th></th>n", "<th>Name</th>n", "<th>Number</th>n", "</tr>n", "</thead>n", "<tbody>n", "<tr>n", "<th>0</th>n", "<td>Alice</td>n", "<td>96</td>n", "</tr>n", "<tr>n", "<th>1</th>n", "<td>Charles</td>n", "<td>155</td>n", "</tr>n", "<tr>n", "<th>2</th>n", "<td>Diane</td>n", "<td>66</td>n", "</tr>n", "<tr>n", "<th>3</th>n", "<td>Edward</td>n", "<td>272</td>n", "</tr>n", "</tbody>n", "</table>n", "</div>" ], "text/plain": [ " Name Numbern", "0 Alice 96n", "1 Charles 155n", "2 Diane 66n", "3 Edward 272" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], The graphic output cell that is stored like this: { "cell_type": "code", "execution_count": 27, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "<matplotlib.axes._subplots.AxesSubplot at 0x47cf8f0>" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "<a few hundred lines of hexcodes> …/wc/B0RRYEH0EQAAAABJRU5ErkJggg==n", "text/plain": [ "<matplotlib.figure.Figure at 0x47d8e30>" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# plot the datan", "df['Number'].plot()n" ] } ], Where the image/png tag contains a large hex digit string representation of the graphical image displayed on screen (I abbreviated the display in the coding shown). So, the actual generated image is stored in the metadata for the page. Python random numbers in Jupyter For many analyses we are interested in calculating repeatable results. However, much of the analysis relies on some random numbers to be used. In Python, you can set the seed for the random number generator to achieve repeatable results with the random_seed() function. In this example, we simulate rolling a pair of dice and looking at the outcome. We would example the average total of the two dice to be 6—the halfway point between the faces. The script we are using is this: import pylab import random random.seed(113) samples = 1000 dice = [] for i in range(samples): total = random.randint(1,6) + random.randint(1,6) dice.append(total) pylab.hist(dice, bins= pylab.arange(1.5,12.6,1.0)) pylab.show() Once we have the script in Jupyter and execute it, we have this result: I had added some more statistics. Not sure if I would have counted on such a high standard deviation. If we increased the number of samples, this would decrease. The resulting graph was opened in a new window, much as it would if you ran this script in another Python development environment. The toolbar at the top of the graphic is extensive, allowing you to manipulate the graphic in many ways. Summary In this article, we walked through simple data access in Jupyter through Python. Then we saw an example of using pandas. We looked at a graphics example. Finally, we looked at an example using random numbers in a Python script. Resources for Article: Further resources on this subject: Python Data Science Up and Running [article] Mining Twitter with Python – Influence and Engagement [article] Unsupervised Learning [article]
Read more
  • 0
  • 0
  • 34017

article-image-understand-how-to-access-the-dark-web-with-tor-browser-tutorial
Savia Lobo
16 Feb 2019
8 min read
Save for later

Understand how to access the Dark Web with Tor Browser [Tutorial]

Savia Lobo
16 Feb 2019
8 min read
According to the Tor Project website: “Tor is free software and an open network that helps you defend against traffic analysis, a form of network surveillance that threatens personal freedom and privacy, confidential business activities and relationships, and state security. The Tor network is a group of volunteer-operated servers that allows people to improve their privacy and security on the Internet. Tor's users employ this network by connecting through a series of virtual tunnels rather than making a direct connection, thus allowing both organizations and individuals to share information over public networks without compromising their privacy. Along the same line, Tor is an effective censorship circumvention tool, allowing its users to reach otherwise blocked destinations or content. Tor can also be used as a building block for software developers to create new communication tools with built-in privacy features.” This article is an excerpt taken from the book, Hands-On Dark Web Analysis written by Sion Retzkin. In this book, you will learn how to install operating systems and Tor Browser for privacy, security, and anonymity while accessing them. In this article, we will understand what Tor and the Tor browser is and how to install it in several ways. Tor (which is an acronym for The Onion Router, by the way) is a privacy-focused network that hides your traffic, by routing it through multiple random servers on the Tor network. So, instead of the packets that make up your communication with another party (person or organization), going from point A to B directly, using Tor, they will jump all over the place, between multiple servers, before reaching point B, hiding the trail. Additionally, the packets that make up the traffic (or communication) in the Tor network are wrapped in special layers, which only show the previous server or step that the packet came from, and the next step, hiding the entire route effectively. Tor Browser is a web browser, based on Firefox that was created for the purpose of accessing the Tor network, securely and privately. Even if you use Tor, this doesn't mean that you're secure. Why is that? Because Tor Browser has software vulnerabilities, the same as every other browser. It's also based on Firefox, so it inherits some of its vulnerabilities from there as well. You can minimize attack vectors by applying common security sense, and by employing various tools to try to limit or prevent malicious activity, related to infecting the Tor Browser or the host running it. Installing Tor on Linux Let's start with a classic installation, by accessing the Tor Project website, via a browser. The default browser that ships with Ubuntu is Firefox, which is what we'll use. Although you might think that this would be the best way to install Tor Browser, it's actually the least secure, since the Tor Project website is continuously targeted by hackers and might have any number of security or privacy issues on it. Instead of just downloading Tor Browser and immediately installing it (which is dangerous), you can either download the file and verify its hash (to verify that it is indeed the correct one), or you could install it through other methods, for example, via the Terminal, by using Linux commands, or from the Ubuntu Software Center. We'll start by going over the steps to download Tor Browser from the Tor Project website: After booting your Linux installation, open your browser Enter the following address and navigate to it: https://www.torproject.org/download/download-easy.html.en#linux. Notice that the URL takes you directly to the Linux download section of the Tor Project website. I usually prefer this direct method, rather than starting with Google (or any other search engine), searching for Tor, and then accessing the Tor Project website, since, as you may know, Google collects information about users accessing it, and the whole idea of this book is to maintain our privacy and security. Also, always verify that you're accessing the Tor Project website via HTTPS. Choose the correct architecture (32 or 64 bit), and click the Download link. You'll be able to choose what you want to do with the file—open it with Ubuntu's Archive Manager, or save it to a location on the disk: Downloading Tor Browser   Again, the quickest way to go would be to open the compressed file, but the more secure way would be to download the file and to verify its hash, before doing anything else. The Tor Project provides GNU Privacy Guard (GPG) signature files, with each version of Tor Browser. You will need to install GnuPG on your Linux OS, if it isn't there already, in order to be able to verify the hash of the browser package. To do so, just open the Terminal and type in the following: sudo apt install gnupg Enter your password when required, and the installation will commence. Most Linux installations already include gnupg, as can be seen in the following screenshot: Installing GnuPG    After installing GnuPG, you need to import the key that signed the package. According to the Tor Project website, the Tor Browser import key is 0x4e2C6e8793298290. The Tor Project updates and changes the keys from time to time, so you can always navigate to:  https://www.torproject.org/docs/verifying-signatures.html.en to find the current import key if the one in the book doesn't work. The command to import the key is as follows: gpg --keyserver pool.sks-keyservers.net --recv-keys 0x4e2C6e8793298290 This is followed by this: gpg --fingerprint 0x4e2C6e8793298290 This will tell you whether the key fingerprint is correct. You should see the following: Verify key fingerprint Now, you need to download the .asc file, which is found on the Tor Browser Downloads page, next to the relevant package of the browser (it appears as sig, short for signature): ASC file location   You can find the Tor Browser download page here: https://www.torproject.org/projects/torbrowser.html Now, you can verify the signature of the package, using the ASC file. To do so, enter the following command in the Terminal: gpg --verify tor-browser-linux64-7.5.6_en-US.tar.xz.asc tor-browser-linux64-7.5.6_en-US.tar.xz Note the 64 that I marked in bold. If your OS is 32-bit, change the number to 32. The result you should get is as follows: Verifying the signature   After verifying the hash (signature) of the Tor Browser package, you can install it. You can do so by either: Double-clicking the Tor Browser package file (which will open up the Archive Manager program), clicking Extract, and choosing the location of your choice. Right-clicking the file and choosing Extract here or Extract to and choosing a location. After extracting, perform the following steps: Navigate to the location you defined. Double-click on the Start-tor-browser.desktop file to launch Tor Browser. Press Trust and Launch in the window that appears: Launching Tor   Notice that the filename and icon changed to Tor Browser. Press Connect and you will be connected to the Tor network, and will be able to browse it, using Tor Browser: Connecting to Tor   Before we discuss using Tor Browser, let's talk about alternative ways to install it, for example, by using the Ubuntu Software application. Start by clicking on the Ubuntu Software icon: Ubuntu Software Search for Tor Browser, then click on the relevant result: Tor Browser in Ubuntu Software Then, click Install. After entering your password, the installation process will start. When it ends, click Launch to start Tor Browser. Installing Tor Browser via the Terminal, from the downloaded package Another way to install Tor is to use commands, via the Terminal. There are several ways to do so, as follows: First, download the required Tor Browser package from the website Verify the download, as we discussed before, and then keep the Terminal open Navigate to the location where you downloaded Tor, by entering the following command: cd path/Tor_Browser_Directory For example, note the following: cd /downloads/tor-browser_en_US Then, launch Tor Browser by running the following: ./start-tor-browser.desktop Never launch Tor as root (or with the sudo command). Installing the Tor Browser entirely via the Terminal Next, we'll discuss how to install Tor entirely via the Terminal: First, launch the Terminal, as before. Then, execute the following command: sudo apt install torbrowser-launcher This command will install the Tor Browser. We need root access to install an app, not to launch it. You can then run Tor by executing the following command: ./start-tor-browser.desktop Thus, in this post, we talked about Tor, Tor Browser, how to install it in several ways, and how to use it. If you've enjoyed this post and want to know more about the concept of the Deep Web and the Dark Web and their significance in the security sector, head over to the book  Hands-On Dark Web Analysis. Tor Project gets its first official mobile browser for Android, the privacy-friendly Tor Browser Tor Browser 8.0 powered by Firefox 60 ESR released How to create a desktop application with Electron [Tutorial]
Read more
  • 0
  • 0
  • 34007

article-image-encrypting-zabbix-traffic
Packt
28 Apr 2016
17 min read
Save for later

Encrypting Zabbix Traffic

Packt
28 Apr 2016
17 min read
In this article by Rihards Olups, the author of the book Zabbix Network Monitoring, Second Edition, we will learn how communication between Zabbix components is done in plaintext by default. In many environments, this is not a significant problem, but monitoring over the Internet in plaintext is likely not a good approach. In previous Zabbix versions, there was no built-in solution, and various VPN, stunnel, and SSH port forwarding solutions were used. Such solutions can still be used, but version 3.0 is the first Zabbix version to provide built-in encryption. In this article, we will set up several of the components to use different methods of encryption. (For more resources related to this topic, see here.) Overview For Zabbix communication encryption, two methods are supported: Preshared Key Certificate-based encryption The Preshared Key (PSK) method is very easy to set up but is likely harder to scale. Certificate-based encryption can be more complicated to set up but easier to manage on a larger scale and potentially more secure. This encryption is supported between all Zabbix components: server, proxy, agent, and even zabbix_sender and zabbix_get. For outgoing connections (such as server-to-agent or proxy-to-server), one method may be used (no encryption, PSK or certificate-based). For incoming connections, multiple methods may be allowed. This way, an agent could work with encryption by default and then turn off encryption with zabbix_get for debugging. Backend libraries Behind the scenes, Zabbix encryption can use one of three different libraries: OpenSSL, GnuTLS, or mbedTLS. Which one to choose? If using packages, the easiest and safest method is to start with whichever one the packages are compiled with. If compiling from source, choose the one that is easiest to compile with. The Zabbix team has made a significant effort of implementing support for all three libraries to look as similar as possible from the user's perspective. There could be differences regarding support for some specific features, but those are likely to be more obscure ones; if such problems do come up later, switching from one library to another should be fairly easy. While in most cases it would likely not matter much which library you are using, it's a good idea to know it—one good reason for supporting these three different libraries is also the ability to switch to a different library if the currently used one has a security vulnerability. These libraries are used in a generic manner, and you don't need to use the same library for different Zabbix components—it's totally fine to use one library on the Zabbix server, another on the Zabbix proxy, and yet another with zabbix_sender. In this article, we will try out encryption with the Zabbix server and zabbix_sender first, then move on to encrypting agent traffic using both PSK and certificate-based encryption. If you have installed from the packages, your server most likely already supports encryption. Verify this by looking at the server and agent startup messages: TLS support:         YES If you compiled from source and there is no TLS support, recompile the server and agent adding one of these parameters: --with-openssl, --with-gnutls, or --with-mbedtls. Preshared key encryption Let's start with a simple situation: a single new host that will accept PSK-encrypted connections only, to which we will send some values using zabbix_sender. For this to work, both the Zabbix server and zabbix_sender must be compiled with Transport Layer Security (TLS) support. The PSK configuration consists of a PSK identity and key. The identity is a string that is not considered to be secret—it is not encrypted during the communication, so do not put sensitive information in the identity string. The key is a hexadecimal string. Zabbix requires the key it to be at least 32 characters long. The maximum in Zabbix is 512 characters, but it might depend on the specific version of the backend library you are using. We could just type the key in manually, but a slightly easier method is using the openssl command: $ openssl rand -hex 64 This will generate a 512-byte key, which we will use in a moment. Navigate to Configuration | Hosts, click on Create host, and fill in these values: Hostname: An encrypted host Groups: Have only Linux Servers in the In Groups block Switch to the Encryption tab, and in the Connections from host section, leave only PSK marked. In the PSK identity field, enter secret, and paste the key we generated earlier in the PSK field:   When done, click on the Add button at the bottom. Take a look at the AGENT ENCRYPTION column for this host: The first block has only one field and currently says NONE. For connections to the agent, only one method is possible; thus, this column must be showing the currently selected method for outgoing connections from the server's perspective. The second block has three fields. We can choose a combination of incoming connection methods; thus, this column must be showing which types of incoming connections from the server's perspective are accepted for this host. Now, click on Items next to Encrypted host, and click on Create item. Fill in these values: Name: Beers in the fridge Type: Zabbix trapper Key: fridge.beers Click on the Add button at the bottom. Let's try to send a value now using following command: $ zabbix_sender -z 127.0.0.1 -s "Encrypted host" -k fridge.beers -o 1 It should fail and show you the following message: info from server: "processed: 0; failed: 1; total: 1; seconds spent: 0.000193" Notice how the processed count is 0 and the failed count is 1. Let's check the Zabbix server logfile: 12254:20160122:231030.702 connection of type "unencrypted" is not allowed for host "Encrypted host" item "fridge.beers" (not every rejected item might be reported) Now this is actually quite a helpful message—we did not specify any encryption for zabbix_sender, but we did require encrypted connection for our host. Notice the text in parentheses—if multiple items on the same host fail because of this reason, we might only see some of them, and searching the logfile by item key only might not reveal the reason. Now is the time to get the PSK working for zabbix_sender. Run it with the --help parameter and look at the TLS connection options section. Oh yes, there's quite a lot of those. Luckily, for PSK encryption, we only need three of them: --tls-connect, --tls-psk-identity, and tls-psk-file. Before running the command, create a file called zabbix_encrypted_host_psk.txt and paste the hex key we generated earlier into it. It is more secure to create an empty file first, change its permissions to 400 or 600, and paste the key in the file afterwards. This way, another user won't have a chance to snatch the key from the file. Run zabbix_sender again, but with the three additional encryption parameters we just set: $ zabbix_sender -z 127.0.0.1 -s "Encrypted host" -k fridge.beers -o 1 --tls-connect psk --tls-psk-identity secret --tls-psk-file zabbix_encrypted_host_psk.txt With this command, we set the connection method to psk with the --tls-connect flag and specified the PSK identity and key file. Zabbix does not support specifying the PSK key on the command line for security reasons. It must be passed in from a file. This time, the value should be sent successfully: info from server: "processed: 1; failed: 0; total: 1; seconds spent: 0.000070" To be sure, verify that this item now has data in the frontend. Certificate-based encryption With PSK-based encryption protecting our sensitive Zabbix trapper item, let's move to the certificates. We will generate certificates for the Zabbix server and agent and require encrypted connections on the Zabbix agent side for passive items. You might have a certificate infrastructure in your organization, but for our first test, we will generate all required certificates ourselves. We will need a new Certificate Authority (CA) that will sign our certificate. Zabbix does not support self-signed certificates. It is highly recommended to use intermediate certificate authorities to sign client and server certificates. We will not use them in the following simple example. Being our own authority We'll start by creating the certificates in a separate directory. For simplicity's sake, let's do this on a test host. The following is not intended to be a good practice. It is actually doing quite a few bad and insecure things to obtain the certificates faster. Do not follow these steps for any production setup: $ mkdir zabbix_ca $ chmod 700 zabbix_ca $ cd zabbix_ca Generate the root CA key: $ openssl genrsa -aes256 -out zabbix_ca.key 4096 When prompted, enter a password twice to protect the key. Generate and self-sign the root certificate like this: $ openssl req -x509 -new -key zabbix_ca.key -sha256 -days 3560 -out zabbix_ca.crt When prompted, enter the password you used for the key before. Fill in the values as prompted—the easiest way is supplying empty values for most except the country code and common name. The common name does not have to be anything too meaningful for our test, so using a simple string such as zabbix_ca will suffice. Now, let's move on to creating a certificate we will use for the Zabbix server; first, let's generate server key and Certificate Signing Request (CSR): $ openssl genrsa -out zabbix_server.key 2048 $ openssl req -new -key zabbix_server.key -out zabbix_server.csr When prompted, enter the country code and the common name string as before. The common name does not have to match the server or agent name or anything else, so using a simple string such as zabbix_server will suffice. Now, let's sign this request: $ openssl x509 -req -in zabbix_server.csr -CA zabbix_ca.crt -CAkey zabbix_ca.key -CAcreateserial -out zabbix_server.crt -days 1460 -sha256 When prompted, enter the CA passphrase. Let's continue with the certificate we will use for the Zabbix agent. Generate the agent key and certificate signing request: $ openssl genrsa -out zabbix_agent.key 2048 $ openssl req -new -key zabbix_agent.key -out zabbix_agent.csr Again, when prompted, enter the country code and common name string as before. The common name does not have to match the server or agent name or anything else, so using a simple string such as zabbix_agent will suffice. Let's sign the request: $ openssl x509 -req -in zabbix_agent.csr -CA zabbix_ca.crt -CAkey zabbix_ca.key -CAcreateserial -out zabbix_agent.crt -days 1460 -sha256 When prompted, enter the CA passphrase. We're done with creating our test certificates. Both keys were created unencrypted. Zabbix does not support prompting for the key password at this time. Setting up Zabbix with certificates Now, we move on to making the passive items on our test host using the certificates we just generated. We must provide the certificates to the Zabbix agent. In the directory where the Zabbix agent configuration file is located, create a new directory called zabbix_agent_certs. Restrict access to it like this: # chown zabbix zabbix_agent_certs # chmod 500 zabbix_agent_certs From the directory where we generated the certificates, copy the relevant certificate files over to the new directory: # cp zabbix_ca.crt /path/to/zabbix_agent_certs/ # cp zabbix_agent.crt /path/to/zabbix_agent_certs/ # cp zabbix_agent.key /path/to/zabbix_agent_certs/ Edit zabbix_agentd.conf and modify these parameters: TLSAccept=cert TLSConnect=unencrypted TLSCAFile=/path/to/zabbix_agent_certs/zabbix_ca.crt TLSCertFile=/path/to/zabbix_agent_certs/zabbix_agent.crt TLSKeyFile=/path/to/zabbix_agent_certs/zabbix_agent.key This will make the agent only accept connections when they are encrypted and use a certificate signed by that CA, either directly or through intermediates. We'll still use unencrypted connections for active items. A user could supply certificates and expect all communication to be encrypted now, which would not be the case if both the TLSAccept and TLSConnect parameters did not require it; thus, Zabbix enforces them when certificates are supplied. Restart the Zabbix agent. Let's take a look at the host configuration list in the Zabbix frontend: Looks like connections to our test host do not work anymore. Let's check the agent logfile: 2820:20160125:194427.623 failed to accept an incoming connection: from 127.0.0.1: unencrypted connections are not allowed Looks like we broke it. We did set up encryption on the agent but did not get to configuring the server side. What if we would like to roll out encryption to all the agents and deal with the server later? In that case, it would be best to set TLSAccept=cert, unencrypted. Then, the agent would still accept unencrypted connections from our server. Once the certificates were deployed and configured on the Zabbix server, we'd only have to remove unencrypted from that parameter and restart the Zabbix agents. Let's try this out—change zabbix_agentd.conf again: TLSAccept=cert, unencrypted Restart the agent daemon and observe the monitoring resuming from the Zabbix server. Now let's make the server use its certificate. We'll place the certificate in a place where the Zabbix server can use it. In the directory where the Zabbix server configuration file is located, create a new directory called zabbix_server_certs. Restrict access to it using these commands: # chown zabbix zabbix_server_certs # chmod 500 zabbix_server_certs If using packages that run the Zabbix server with a different username such as zabbixs or zabbixserv, replace the username in these two commands. From the directory where we generated the certificates, copy them over to the new directory: # cp zabbix_ca.crt /path/to/zabbix_server_certs/ # cp zabbix_server.crt /path/to/zabbix_server_certs/ # cp zabbix_server.key /path/to/zabbix_server_certs/ Edit zabbix_server.conf and modify these parameters: TLSCAFile=/path/to/zabbix_server_certs/zabbix_ca.crt TLSCertFile=/path/to/zabbix_server_certs/zabbix_server.crt TLSKeyFile=/path/to/zabbix_server_certs/zabbix_server.key Now, restart the Zabbix server. Although we have specified the certificates in both the agent and server, the passive items still work in unencrypted mode. Let's proceed with making them encrypted. In the Zabbix frontend, navigate to Configuration | Hosts, click on A test host, and switch to the Encryption tab. In the Connections to host selection, choose Certificate, then click on the Update button. After the server configuration cache is updated, it will switch to using certificate-based encryption for this host. Going back to our scenario where we slowly rolled out certificate-based configuration to our agents and added it to the server later, we can now disable unencrypted connections on the agent side. Change this line in zabbix_agentd.conf: TLSAccept=cert Restart the agent. If we had followed this process from the very beginning, monitoring would have continued uninterrupted. Let's try to use zabbix_get: $ zabbix_get -s 127.0.0.1 -k system.cpu.load zabbix_get [5746]: Check access restrictions in Zabbix agent configuration That fails because agent only accepts encrypted connections now. Like we did for zabbix_sender, we can specify the certificate, but we must use the Zabbix server certificate now: $ zabbix_get -s 127.0.0.1 -k system.cpu.load --tls-connect cert --tls-ca-file /path/to/zabbix_server_certs/zabbix_ca.crt --tls-cert-file /path/to/zabbix_server_certs/zabbix_server.crt --tls-key-file /path/to/zabbix_server_certs/zabbix_server.key 0.030000 Certainly, this results in a more secure environment. It is not enough to spoof the IP address to access this agent. It is not enough to have an account on the Zabbix server to have access to all agents—access to the server certificate is required, too. On the other hand, it makes debugging a bit more complicated. We used PSK and certificate-based encryption with zabbix_sender and passive agent, but the same principles apply for active agents and zabbix_get. As an exercise, try to get the active agent items working with encryption too. Concerns and further reading At this time, encryption is a very new feature in Zabbix. While it has been developed and tested extremely carefully and pedantically, it is likely to receive further improvements. Make sure to read through the official documentation on encryption for more details and in case of changes being made. Right now, we will touch upon basic concerns and features that are missing. In this article, we covered the Zabbix server, agent, zabbix_get and zabbix_sender—what about Zabbix proxies? Zabbix proxies fully support encryption. The configuration on the proxy side is very similar to the agent configuration, and the configuration on the server or frontend side is done in a similar way to host encryption configuration, too. Keep in mind that all involved components must be compiled with TLS support—any proxies you have might have to be recompiled. When considering encryption, think about the areas where it's needed most: maybe you have Zabbix server and proxy communicating over the Internet while all other connections are in local networks. In that case, it might make sense to set up encryption only for server-proxy communication at first. Note that encryption is not supported when communicating with the Zabbix Java gateway, but one could easily have the gateway communicate with the Zabbix proxy on the localhost, which in turn provides encryption for the channel to the Zabbix server. We already figured out how the upgrading and transitioning to encryption can happen seamlessly without interrupting data collection—the ability of all components to accept various connection types allows us to roll the changes out sequentially. Another reason why one might want to implement encryption only partially is performance. Currently, Zabbix does not reuse connections, implement TLS session caches, or use any other mechanism that would avoid setting up encrypted connections from scratch every time. This can be especially devastating if you have lots of passive agent items. Make sure to understand the potential impact before reconfiguring it all. Encryption is not currently supported for authentication purposes. That is, we can not omit active agent hostnames and figure out which host it is based on the certificate alone. Similarly, we can not allow only encrypted connections for active agent auto-registration. For certificate-based encryption, we only specified the certificates and CA information. If the CA used is large enough, it would not be very secure: any certificate signed by that CA would be accepted. Zabbix also allows verifying both the issuer and subject of the remote certificate. Unless you are using an internal CA that is used for Zabbix only, it is highly recommended you limit issuers and subjects. Summary In this article, we explored Zabbix's built-in encryption, which is supported between all components: the server, proxy, agent, zabbix_sender, and zabbix_get. While not supported for the Java gateway, a Zabbix proxy could easily be put in front of the gateway to provide encryption back to the Zabbix server. Zabbix supports PSK and TLS certificate-based encryption and can use one of three different backend libraries: OpenSSL, GnuTLS, or mbedTLS. In case of security or other issues with one library, users have an option of switching to another library. The upgrade and encryption deployment can be done in steps. All Zabbix components can accept multiple connection methods at the same time. In our example, the agent would be set up to accept both encrypted and unencrypted connections, and when we would be done with all agents, we would switch to encrypted connections on the server side. Once that would be verified to work as expected, unencrypted connections could be disabled on the agents. With the encryption being built-in and easy to set up, it is worth remembering that encrypted connections will need more resources and that Zabbix does not support connection pooling or other methods that could decrease the load. It might be worth securing the most important channels first, leaving endpoints for later. For example, encrypting the communication between the Zabbix server and proxies would likely be a priority over connections to individual agents. Resources for Article:   Further resources on this subject: Deploying a Zabbix proxy [article] Zabbix Configuration [article] Monitoring Windows with Zabbix 1.8 [article]
Read more
  • 0
  • 0
  • 33970
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-started-with-openai-whisper
Vivekanandan Srinivasan
30 Oct 2023
9 min read
Save for later

Getting Started with OpenAI Whisper

Vivekanandan Srinivasan
30 Oct 2023
9 min read
Dive deeper into the world of AI innovation and stay ahead of the AI curve! Subscribe to our AI_Distilled newsletter for the latest insights. Don't miss out – sign up today!IntroductionIn the era of rapid technological advancements, speech recognition technology has emerged as a game-changer, revolutionizing how we interact with machines and devices.As we know, OpenAI has developed an exceptional Automatic Speech Recognition (ASR) system known as OpenAI Whisper.In this blog, we will deeply dive into Whisper, understanding its capabilities, applications, and how you can harness its power through the Whisper API.Understanding OpenAI WhisperWhat is OpenAI Whisper?Well, put-“You Speak…AI Writes” OpenAI Whisper is an advanced ASR system that converts spoken language into written text.Built on cutting-edge technology and trained on 680,000 hours of multilingual and multitask supervised data collected from the web, OpenAI Whisper excels in a wide range of speech recognition tasks, making it a valuable tool for developers and businesses.Why Does ASR (Automatic Speech Recognition) Matter?Automatic Speech Recognition (ASR) is not just a cutting-edge technology; it's a game-changer reshaping how we interact with our digital world. Imagine a world where your voice can unlock a wealth of possibilities. That's what ASR, with robust systems like Whisper leading the charge, has made possible.Let's dive deeper into the ASR universe.It's not just about making life more convenient; it's about leveling the playing field. ASR technology is like the magic wand that enhances accessibility for individuals with disabilities. It's the backbone of those voice assistants you chat with and the transcription services that make your voice immortal in text.But ASR doesn't stop there; it's a versatile tool taking over various industries. Picture this: ASR helps doctors transcribe patient records in healthcare with impeccable accuracy and speed. That means better care for you. And let's remember the trusty voice assistants like Siri and Google Assistant, always at your beck and call, answering questions and performing tasks, all thanks to ASR's natural language interaction wizardry. Setup and InstallationWhen embarking on your journey to harness the remarkable power of OpenAI Whisper for Automatic Speech Recognition (ASR), the first crucial step is to set up and install the necessary components.In this section, we will guide you through starting with OpenAI Whisper, ensuring you have everything in place to begin transcribing spoken words into text with astonishing accuracy.Prerequisites Before you dive into the installation process, it's essential to make sure you have the following prerequisites in order:OpenAI Account To access OpenAI Whisper, you must have an active OpenAI account. If you still need to sign up, visit the OpenAI website and create an account.API Key You will need an API key from OpenAI to make API requests. This key acts as your access token to use the Whisper ASR service. Ensure you have your API key ready; if you don't have one, you can obtain it from your OpenAI account.Development Environment It would help to have a functioning development environment for coding and running API requests. You can use your preferred programming language, Python, to interact with the Whisper API. Make sure you have the necessary libraries and tools installed.Installation Steps Now, let's walk through the steps to install and set up OpenAI Whisper for ASR:1. Install the OpenAI Python LibraryIf you haven't already, you must install the OpenAI Python library. This library simplifies the process of making API requests to OpenAI services, including Whisper. You can install it using pip, the Python package manager, by running the following command in your terminal: pip install openai2. Authenticate with Your API KeyYou must authenticate your requests with your API key to interact with the Whisper ASR service. You can do this by setting your API key as an environment variable in your development environment or by directly including it in your code. Here's how you can set the API key as an environment variable:import openai openai.api_key = "YOUR_API_KEY_HERE" Replace "YOUR_API_KEY_HERE" with your actual API key.3. Make API RequestsWith the OpenAI Python library installed and your API key adequately set, you can now start making API requests to Whisper. You can submit audio files or chunks of spoken content and receive transcriptions in response. import openai response = openai.Transcription.create( model="whisper", audio="YOUR_AUDIO_FILE_URL_OR_CONTENT", language="en-US"  # Adjust language code as needed ) print(response['text']) Replace "YOUR_AUDIO_FILE_URL_OR_CONTENT" with the audio source you want to transcribe.Testing Your SetupAfter following these installation steps, testing your setup with a small audio file or sample content is a good practice.This will help you verify that everything functions correctly and that you can effectively convert spoken words into text.Use Cases And ApplicationsTranscription ServicesWhisper excels in transcribing spoken words into text. This makes it a valuable tool for content creators, journalists, and researchers whose work demands them to convert audio recordings into written documents.Voice Assistants Whisper powers voice assistants and chatbots, enabling natural language understanding and interaction. This is instrumental in creating seamless user experiences in applications ranging from smartphones to smart home devices.AccessibilityWhisper enhances accessibility for individuals with hearing impairments by providing real-time captioning services during live events, presentations, and video conferences.Market ResearchASR technology can analyze customer call recordings, providing businesses with valuable insights and improving customer service.Multilingual SupportWhisper supports multiple languages, making it a valuable asset for global companies looking to reach diverse audiences.Making Your First API CallNow that you have your Whisper API key, it's time to make your first API call. Let's walk through a simple example of transcribing spoken language into text using Python.pythonCopy code:import openai # Replace 'your_api_key' with your actual Whisper API key openai.api_key = 'your_api_key' response = openai.Transcription.create( audio="<https://your-audio-url.com/sample-audio.wav>", model="whisper", language="en-US" ) print(response['text'])In this example, we set up the API key, specify the audio source URL, select the Whisper model, and define the language. The response['text'] contains the transcribed text from the audio.Use CasesLanguage DetectionOne of the remarkable features of OpenAI Whisper is its ability to detect the language being spoken.This capability is invaluable for applications that require language-specific processing, such as language translation or sentiment analysis.Whisper's language detection feature simplifies identifying the language spoken in audio recordings, making it a powerful tool for multilingual applications.TranscriptionTranscription is one of the most common use cases for Whisper. Whether you need to transcribe interviews, podcasts, or customer service calls, Whisper's accuracy and speed make it an ideal choice.Developers can integrate Whisper to automate transcription, saving time and resources.Supported LanguagesOpenAI Whisper supports many languages, making it suitable for global applications. Some supported languages include English, Spanish, French, German, Chinese, and others.Open AI supports all these languages as of now-Afrikaans, Arabic, Armenian, Azerbaijani, Belarusian, Bosnian, Bulgarian, Catalan, Chinese, Croatian, Czech, Danish, Dutch, English, Estonian, Finnish, French, Galician, German, Greek, Hebrew, Hindi, Hungarian, Icelandic, Indonesian, Italian, Japanese, Kannada, Kazakh, Korean, Latvian, Lithuanian, Macedonian, Malay, Marathi, Maori, Nepali, Norwegian, Persian, Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovenian, Spanish, Swahili, Swedish, Tagalog, Tamil, Thai, Turkish, Ukrainian, Urdu, Vietnamese, and Welsh.Best Practices While Using WhisperWhen working with Whisper for longer-format audio or complex tasks, following best practices is essential. For instance, you can break longer audio files into shorter segments for improved accuracy. Additionally, you can experiment with different settings and parameters to fine-tune the ASR system according to your specific requirements.Here's a simple example of how to break down more extended audio for transcription:pythonCopy codeimport openai # Replace 'your_api_key' with your actual Whisper API key openai.api_key = 'your_api_key' # Divide the longer audio into segments audio_segments = [    "<https://your-audio-url.com/segment1.wav>",    "<https://your-audio-url.com/segment2.wav>",    # Add more segments as needed ] # Transcribe each segment separately for segment in audio_segments:    response = openai.Transcription.create(        audio=segment,        model="whisper",        language="en-US"    )    print(response['text'])These best practices and tips ensure you get the most accurate results when using OpenAI Whisper.ConclusionIn this blog, we've explored the incredible potential of OpenAI Whisper, an advanced ASR system that can transform how you interact with audio data. We've covered its use cases, how to access the Whisper API, make your first API call, and implement language detection and transcription. With its support for multiple languages and best practices for optimizing performance, Whisper is a valuable tool for developers and businesses looking to harness the power of automatic speech recognition.In our next blog post, we will delve even deeper into OpenAI Whisper, exploring its advanced features and the latest developments in ASR technology. Stay tuned for "Advances in OpenAI Whisper: Unlocking the Future of Speech Recognition."For now, start your journey with OpenAI Whisper by requesting access to the API and experimenting with its capabilities. The possibilities are endless, and the power of spoken language recognition is at your fingertips.Author BioVivekanandan, a seasoned Data Specialist with over a decade of expertise in Data Science and Big Data, excels in intricate projects spanning diverse domains. Proficient in cloud analytics and data warehouses, he holds degrees in Industrial Engineering, Big Data Analytics from IIM Bangalore, and Data Science from Eastern University.As a Certified SAFe Product Manager and Practitioner, Vivekanandan ranks in the top 1 percentile on Kaggle globally. Beyond corporate excellence, he shares his knowledge as a Data Science guest faculty and advisor for educational institutes. 
Read more
  • 0
  • 0
  • 33968

article-image-following-capital-one-data-breach-github-gets-sued-and-aws-security-questioned-by-a-u-s-senator
Savia Lobo
07 Aug 2019
5 min read
Save for later

Following Capital One data breach, GitHub gets sued and AWS security questioned by a U.S. Senator

Savia Lobo
07 Aug 2019
5 min read
Last week, Capital One revealed it was subject to a major data breach due to a configuration vulnerability in its firewall to access its Amazon S3 database, affecting 106 million users in the US and Canada. A week after the breach, not only Capital One, but GitHub and Amazon are also facing scrutiny for their inadvertent role in the breach. Capital One and GitHub sued in California Last week, the law firm Tycko & Zavareei LLP filed a lawsuit in California's federal district court on behalf of their plaintiffs Seth Zielicke and Aimee Aballo. Both plaintiffs claim Capital One and GitHub were unable to protect user’s personal data. The complaint highlighted that Paige A. Thompson, the alleged hacker stole the data in March, posted about the theft on GitHub in April. According to the lawsuit, “As a result of GitHub’s failure to monitor, remove, or otherwise recognize and act upon obviously-hacked data that was displayed, disclosed, and used on or by GitHub and its website, the Personal Information sat on GitHub.com for nearly three months.” The law firm also alleged that with the help of computer logs, Capital One should have known about the data breach when the information was first stolen in March. They “criticized Capital One for not taking action to respond to the breach until last month,” The Hill reports. The lawsuit also alleges that GitHub “encourages (at least) friendly hacking." "GitHub had an obligation, under California law, to keep off (or to remove from) its site Social Security numbers and other Personal Information," the lawsuit further mentions. According to Newsweek, GitHub also violated the federal Wiretap Act, "which permits civil recovery for those whose 'wire, oral, or electronic communication' has been 'intercepted, disclosed, or intentionally used' in violation of, inter alia, the Wiretap Act." A GitHub spokesperson told Newsweek, "GitHub promptly investigates content, once it's reported to us, and removes anything that violates our Terms of Service." "The file posted on GitHub in this incident did not contain any Social Security numbers, bank account information, or any other reportedly stolen personal information. We received a request from Capital One to remove content containing information about the methods used to steal the data, which we took down promptly after receiving their request," the spokesperson further added. On 30th July, New York Attorney General, Letitia James also announced that her office is opening an investigation into the Capital One data breach. “My office will begin an immediate investigation into Capital One’s breach, and will work to ensure that New Yorkers who were victims of this breach are provided relief. We cannot allow hacks of this nature to become every day occurrences,” James said in a statement. Many are confused about why a lawsuit was filed against GitHub as they believe that GitHub is not at fault. Tony Webster, a journalist, and a public records researcher tweeted, “I genuinely can't tell if this lawsuit is incompetence or malice. GitHub owed no duty to CapitalOne customers. This would be like suing a burglar's landlord because they didn't detect and stop their tenant from selling your stolen TV from their apartment.” https://twitter.com/rickhholland/status/1157658909563379713 https://twitter.com/NSQE/status/1157479467805057024 https://twitter.com/xxdesmus/status/1157679112699277312 A user on HackerNews writes, “This is incredible: they're suggesting that, in the same way that YouTube has content moderators, GitHub should moderate every repository that has a 9-digit sequence. They also say that GitHub "promotes hacking" without any nuance regarding modern usage of the word, and they claim that GitHub had a "duty" to put processes in place to monitor submitted content, and that by not having such processes they were in violation of their own terms of service. I hope that this gets thrown out. If not, it could have severe consequences for any site hosting user-generated content.” Read the lawsuit to know more about this news in detail. U.S. Senator’s letter to Amazon CEO raises questions on the security of AWS products Yesterday, Senator Ron Wyden wrote to Amazon’s CEO, Jeff Bezos “requesting details about the security of Amazon’s cloud service”, the Wall Street Journal reports. The letter has put forth questions to understand how the configuration error occurs and what measures is Amazon taking to protect its customers. The Journal reported, “more than 800 Amazon users were found vulnerable to a similar configuration error, according to a partial scan of cloud users, conducted in February by a security researcher.” According to the Senator’s letter, “When a major corporation loses data on a hundred million Americans because of a configuration error, attention naturally focuses on that corporation’s cybersecurity practices.” “However, if several organizations all make similar configuration errors, it is time to ask whether the underlying technology needs to be made safer and whether the company that makes it shares responsibility for the breaches,” the letter further mentions. Jeff Bezos has been asked to reply to these questions by August 13, 2019. “Amazon has said that its cloud products weren’t the cause of the breach and that it provides tools to alert customers when data is being improperly accessed,” WSJ reports. Capital One did not comment on this news. Read the complete letter to know more in detail. U.S. Senator introduces a bill that levies jail time and hefty fines for companies violating data breaches Facebook fails to fend off a lawsuit over data breach of nearly 30 million users Equifax breach victims may not even get the promised $125; FTC urges them to opt for 10-year free credit monitoring services
Read more
  • 0
  • 0
  • 33967

article-image-style-management-qgis
Packt
06 Jul 2015
11 min read
Save for later

Style Management in QGIS

Packt
06 Jul 2015
11 min read
In this article by Alexander Bruy and Daria Svidzinska, authors of the book QGIS By Example, you will learn how to work with styles, including saving and loading them, using different styles, and working with the Style Manager. (For more resources related to this topic, see here.) Working with styles In QGIS, a style is a way of cartographic visualization that takes into account a layer’s individual and thematic features. It encompasses basic characteristics of symbology, such as the color and presence of fill, outline parameters, the use of markers, scale-dependent rendering, layer transparency, and interactions with other layers. Style incorporates not only rendering appearance, but also other things, such as labeling settings. A well-chosen style greatly simplifies data perception and readability, so it is important to learn how to work with styles to be able to represent your data the best way. Styling is an important part of data preparation, and QGIS provides many handy features that make this process much more productive and easier. Let’s look at some of them! Saving and loading styles Creating good-looking styles can be a time-consuming task, but the good thing is that once developed styles don’t go to nowhere. You can save them for further use in other projects. When you have finished polishing your style, it is wise to save it. Usually, this is done from the Layer Properties dialog, which can be opened from the layer's context menu. There is a Style button at the bottom of this dialog. It provides access to almost all actions that can be performed with the layer's style, including saving, loading, making the style default, and so on. The style can be saved to the file on the disk (this works for any layer type), or stored in the database (possible only for database-based layers). To save style in the file, perform these steps: Open the Layer Properties dialog. Click on the Style button at the bottom of the Properties dialog and go to the Save Style submenu: Choose one of the available formats. A standard file dialog will open. Navigate to the desired location in your filesystem and save the style. Currently QGIS provides support for the following formats of saving styles: QGIS style file: The style is saved as a .qml file, which is a native QGIS format used to store symbology definition and other layer properties. Style Layer Descriptor (SLD) file: The style is exported to a .sld file. SLD format is widely used in web cartography, for example, by applications such as GeoServer. It is necessary to mention that currently, SLD support in QGIS is a bit limited. Also, you should remember that while you can save any style (or renderer type) in SLD, during import, you will get either a rule-based or a single-symbol renderer. If you work with the spatial database, you may want to save layer styles in the same database, together with layers. Such a feature is very useful in corporate environments, as it allows you to assign multiple styles for a single layer and easily keep the styles in sync. Saving styles in the database currently works only for PostgreSQL and SpatiaLite. To save style in the database, follow these steps: Open the Layer Properties dialog. Click on the Style button at the bottom of the Properties dialog and go to the Save Style submenu. Select the Save in database (format) item, where format can be spatialite or postgres, depending on the database type: The Save style in database dialog opens. Enter the style name and (optional) description in the corresponding fields, and click on the OK button to save the style: The saved style can be loaded and applied to the layer. To load a style from the file, use these steps: Open the Layer Properties dialog from the context menu. Click on the Style button at the bottom of the Properties dialog and select the Load Style item. Choose the style file to load. Loading a style from the database is a bit different: Open the Layer Properties dialog from the context menu. Click on the Style button at the bottom of the Properties dialog and go to Load Style | From database. The Load style from database dialog opens. Select the style you want to load and click on the Load Style button. With all of these options, we can easily save styles in the format that meets our requirements and tasks. Copy and paste styles Very often, you need to apply mostly the same style with really minor differences to multiple layers. There are several ways of doing this. First, you can save the style (as described in the previous section) in one of the supported formats, and then apply this saved style to another layer and edit it. But there is simpler way. Starting from QGIS 1.8, you can easily copy and paste styles between layers. To copy a style from one layer to another, perform these steps: In the QGIS layer tree, select the source layer from which you want to copy the style. Right-click to open the context menu. Go to Styles | Copy Style to copy the style of the source layer to the clipboard. Now, in the QGIS layer tree, select the target layer. Right-click to open its context menu. Go to Styles | Paster Style to paste the previously copied style from the clipboard and apply it to the target layer. It is important to note that QGIS allows you to copy, for example, a polygonal style and apply it to a point or line layer. This may lead to incorrect layer rendering, or the layer can even disappear from the map even though it still present in the layer tree. Instead of using the layer context menu to copy and paste styles, you can use the QGIS main menu. Both of these actions (Copy Style and Paste Style) can be found in the Layer menu. The copied style can be pasted in a text editor. Just copy the style using the context menu or QGIS main menu, open the text editor, and press Ctrl + V (or another shortcut used in your system to paste data from the clipboard) to paste the style. Now you can study it. Also, with this feature, you can apply the same style to multiple layers at once. Copy the style as previously described. Then select in the QGIS layer tree all the layers that you want to style (use the Ctrl key and/or the Shift key to select multiple layers). When all the desired layers are selected, go to Layer | Paste Style. Voilà! Now the style is applied to all selected layers. Using multiple styles per layer Sometimes, you may need to show the same data with different styles on the map. The most common and well-known solution to do this is to duplicate the layer in the QGIS layer tree and change the symbology. QGIS 2.8 allows us to achieve the same result in a simpler and more elegant way. Now we can define multiple styles for a single layer and easily switch between them when necessary. This functionality is available from the layer context menu and the layer Properties dialog. By default, all layers have only one style, called default. To create an additional style, use these steps: Select the layer in the layer tree. Right-click to open the context menu. Go to Styles | Add. The New style dialog opens. Enter the name of the new style and click on OK: A new style will be added and become active. It is worth mentioning that after adding a new style, the layer's appearance will remain the same, as the new style inherits all the properties of the active style. Adjust the symbology and other settings according to your needs. These changes will affect only the current style; previously created styles will remain unchanged. You can add as many styles as you want. All available styles are listed in the layer context menu, at the bottom of the Styles submenu. The current (or active) style is marked with a checkbox. To switch to another style, just select its name in the menu. If necessary, you can rename the active style (go to Styles | Rename Current) or remove it (go to Styles | Remove Current). Also, the current style can be saved and copied as previously described. Moreover, it is worth mentioning that multiple styles are supported by the QGIS server. The available layer styles are displayed via the GetCapabilities response, and the user can request them in, for example, the GetMap request. This handy feature also works in the Print Composer. Using Style manager Style manager provides extended capabilities for symbology management, allowing the user to save developed symbols; tag and merge them into thematic groups; and edit, delete, import, or export ready-to-use predefined symbology sets. If you created a symbol and want it to be available for further use and management, you should first save it to the Symbol library by following these steps: In the Style section of the layer Properties window, click on the Save button underneath the symbol preview window. In the Symbol name window, type a name for the new symbol and click on OK: After that, the symbol will appear and become available from the symbol presets in the right part of the window. It will also become available for the Style Manager. The Style Manger window can be opened by: Clicking on the Open library button after going to Properties | Style Going to Settings | Style Manager The window consists of three sections: In the left section, you can see a tree view of the available thematic symbology groups (which, by default, don't contain any user-specified groups) In the right part, there are symbols grouped on these tabs: Marker (for point symbols), Line (for line symbols), Fill (for polygon symbols), and Color ramp (for gradient symbols). If you double-click on any symbol on these tabs, the Symbol selector window will be opened, where you can change any available symbol properties (Symbol layer type, Size, Fill and Outline colors, and so on). Similarly, you can use the Edit button to change the appearance of the symbol. The bottom section of the window contains symbol management buttons—Add, Remove, Edit, and Share—for groups and their items. Let's create a thematic group called Hydrology. It will include symbology for hydrological objects, whether they are linear (river, canal, and so on) or polygonal (lake, water area, and so on). For this, perform the following steps: Highlight the groups item in the left section of the Style manager window and click on the very first + button. When the New group appears, type the Hydrology name. Now you need to add some symbols to the newly emerged group. There are two approaches to doing this: Right-click on any symbol (or several by holding down the Ctrl key) you want to add, and select from its contextual shortcut Apply Group | Hydrology. Alternatively, highlight the Hydrology group in the groups tree, and from the button below, select Group Symbols, as shown in this screenshot: As a result, checkboxes will appear beside the symbols, and you can toggle them to add the necessary symbol (or symbols) to the group. After you have clicked on the Close button, the symbols will be added to the group. Once the group is created, you can use it for quick access to the necessary symbology by going to Properties | Style | Symbols in group, as shown in the following screenshot: Note that you can combine the symbology for different symbology types within a single group (Marker, Line, Fill, and Color ramp), but when you upload symbols in this group for a specific layer, the symbols will be filtered according to the layer geometry type (for example, Fill for the polygon layer type). Another available option is to create a so-called Smart Group, where you can flexibly combine various conditions to merge symbols into meaningful groups. As an example, the following screenshot shows how we can create a wider Water group that includes symbols that are not only present in Hydrology already, but are also tagged as blue: Use the Share button to Export or Import selected symbols from external sources. Summary This article introduced the different aspects of style management in QGIS: saving and loading styles, copying and pasting styles, and using multiple styles per layer. Resources for Article: Further resources on this subject: How Vector Features are Displayed [article] Geocoding Address-based Data [article] Editing attributes [article]
Read more
  • 0
  • 0
  • 33960

article-image-10-commandments-for-effective-ux-design
Will Grant
11 Mar 2019
8 min read
Save for later

Will Grant’s 10 commandments for effective UX Design

Will Grant
11 Mar 2019
8 min read
Somewhere along the journey of web maturity, we forgot something important: user experience is not art. It's the opposite of art. UX design should perform one primary function: serving users. Your UX design has to look great, but it should not be at the expense of hampering the working of the website. This is an extract from 101 UX Principles by Will Grant. Read our interview with Will here. #1 Empathy and objectivity are the primary skills of a  UX professional Empathy and objectivity are the primary skills you must possess to be good at UX. This is not to undermine those who have spent many years studying and working in the UX field — their insights and experience are valuable — rather say that study and practice alone are not enough. You need empathy to understand your users’ needs, goals, and frustrations. You need objectivity to look at your product with fresh eyes, spot the flaws and fix them. You can learn everything else. Read More: Soft skills every data scientist should teach their child #2 Don’t use more than two typefaces Too often designers add too many typefaces to their products. You should aim to use two typefaces maximum: one for headings and titles, and another for body copy that is intended to be read. Using too many typefaces creates too much visual ‘noise’ and increases the effort that the user has to put into understanding the view in front of them. What’s more, many custom-designed brand typefaces are made with punchy visual impact in mind, not readability. Use weights and italics within that font family for emphasis, rather than switching to another family. Typically, this means using your corporate brand font as the heading, while leaving the controls, dialogs and in-app copy (which need to be clearly legible) in a more proven, readable typeface. #3 Make your buttons look like buttons There are parts of your UI that can be interacted with, but your user doesn’t know which parts and doesn’t want to spend time learning. Flat design is bad. It’s really terrible for usability. It’s style over substance and it forces your users to think more about every interaction they make with your product. Stop making it hard for your customers to find the buttons! By drawing on real-world examples, we can make UI buttons that are obvious and instantly familiar. By using real-life inspiration to create affordances, a new user can identify the controls right away. Create the visual cues your user needs to know instantly that they’re looking at a button that can be tapped or clicked. #4 Make ‘blank slates’ more than just empty views The default behavior of many apps is to simply show an empty view where the content would be. For a new user, this is a pretty poor experience and a massive missed opportunity for you to give them some extra orientation and guidance. The blank slate is only shown once (before the user has generated any content). This makes it an ideal way of orienting people to the functions of your product while getting out of the way of more established users who will hopefully ‘know the ropes’ a little better. For that reason, it should be considered mandatory for UX designers to offer users a useful blank slate. #5 Hide ‘advanced’ settings from most users There’s no need to include every possible menu option on your menu when you can hide advanced settings away. Group settings together but separate out the more obscure ones for their own section of ‘power user’ settings. These should also be grouped into sections if there are a lot of them (don’t just throw all the advanced items in at random). Not only does hiding advanced settings have the effect of reducing the number of items for a user to mentally juggle, but it also makes the app appear less daunting, by hiding complex settings from most users. By picking good defaults, you can ensure that the vast majority of users will never need to alter advanced settings. For the ones that do, an advanced menu section is a pretty well-used pattern. #6 Use device-native input features where possible If you’re using a smartphone or tablet to dial a telephone number, the device’s built-in ‘phone’ app will have a large numeric keypad, that won’t force you to use a fiddly ‘QWERTY’ keyboard for numeric entry. Sadly, too often we ask users to use the wrong input features in our products. By leveraging what’s already there, we can turn painful form entry experiences into effortless interactions. No matter how good you are, you can’t justify spending the time and money that other companies have spent on making usable system controls. Even if you get it right, it’s still yet another UI for your user to learn, when there’s a perfectly good one already built into their device. Use that one. #7 Always give icons a text label Icons are used and misused so relentlessly, across so many products, that you can’t rely on any 'one' single icon to convey a definitive meaning. For example, if you’re offering a ‘history’ feature,  there’s a wide range of pictogram clocks, arrows, clocks within arrows, hourglasses, and parchment scrolls to choose from. This may confuse the user and hence you need to add a text label to make the user understand what this icon means in this context within your product. Often, a designer will decide to sacrifice the icon label on mobile responsive views. Don’t do this. Mobile users still need the label for context. The icon and the label will then work in tandem to provide context and instruction and offer a recall to the user, whether they’re new to your product or use it every day. #8 Decide if an interaction should be obvious, easy or possible To help decide where (and how prominently) a control or interaction should be placed, it’s useful to classify interactions into one of three types. Obvious Interactions Obvious interactions are the core function of the app, for example, the shutter button on a camera app or the “new event” button on a calendar app. Easy Interactions An easy interaction could be switching between the front-facing and rear-facing lens in a camera app, or editing an existing event in a calendar app. Possible Interactions Interactions we classify as possible are rarely used and they are often advanced features. For example, it is possible to adjust the white balance or auto-focus on a camera app or make an event recurring on a calendar app. #9 Don’t join the dark side So-called ‘dark patterns’ are UI or UX patterns designed to trick the user into doing what the corporation or brand wants them to do. These are, in a way, exactly the same as the scams used by old-time fraudsters and rogue traders, now transplanted to the web and updated for the post-internet age. Shopping carts that add extra "add-on" items (like insurance, protection policies, and so on) to your cart before you check out, hoping that you won't remove them Search results that begin their list by showing the item they'd like to sell you instead of the best result Ads that don't look like ads, so you accidentally tap them Changing a user's settings—edit your private profile and if you don't explicitly make it private again, the company will switch it back to public Unsubscribe "confirmation screens", where you have to uncheck a ton of checkboxes just right to actually unsubscribe. In some fields, medicine, for example, professionals have a code of conduct and ethics that form the core of the work they do. Building software does not have such a code of conduct, but maybe it should do. #10 Test with real users There’s a myth that user testing is expensive and time-consuming, but the reality is that even very small test groups (less than 10 people) can provide fascinating insights. The nature of such tests is very qualitative and doesn’t lend itself well to quantitative analysis, so you can learn a lot from working with a small sample set of fewer than 10 users. Read More: A UX strategy is worthless without a solid usability test plan You need to test with real users, not your colleagues, not your boss and not your partner. You need to test with a diverse mix of people, from the widest section of society you can get access to. User testing is an essential step to understanding not just your product but also the users you’re testing: what their goals really are, how they want to achieve them and where your product delivers or falls short. Summary In the web development world, UX and UI professionals keep making UX mistakes, trying to reinvent the wheel, and forgetting to put themselves in the place of a user. Following these 10 commandments and applying them to the software design will create more usable and successful products, that look great but at the same time do not hinder functionality. Is your web design responsive? What UX designers can teach Machine Learning Engineers? To start with: Model Interpretability Trends UX Design
Read more
  • 0
  • 0
  • 33959
article-image-ensemble-methods-optimize-machine-learning-models
Guest Contributor
07 Nov 2017
8 min read
Save for later

Ensemble Methods to Optimize Machine Learning Models

Guest Contributor
07 Nov 2017
8 min read
[box type="info" align="" class="" width=""]We are happy to bring you an elegant guest post on ensemble methods by Benjamin Rogojan, popularly known as The Seattle Data Guy.[/box] How do data scientists improve their algorithm’s accuracy or improve the robustness of a model? A method that is tried and tested is ensemble learning. It is a must know topic if you claim to be a data scientist and/or a machine learning engineer. Especially, if you are planning to go in for a data science/machine learning interview. Essentially, ensemble learning stays true to the meaning of the word ‘ensemble’. Rather than having several people who are singing at different octaves to create one beautiful harmony (each voice filling in the void of the other), ensemble learning uses hundreds to thousands of models of the same algorithm that work together to find the correct classification. Another way to think about ensemble learning is the fable of the blind men and the elephant. Each blind man in the story seeks to identify the elephant in front of them. However, they work separately and come up with their own conclusions about the animal. Had they worked in unison, they might have been able to eventually figure out what they were looking at. Similarly, ensemble learning utilizes the workings of different algorithms and combines them for a successful and optimal classification. Ensemble methods such as Boosting and Bagging have led to an increased robustness of statistical models with decreased variance. Before we begin with explaining the various ensemble methods, let us have a glance at the common bond between them, Bootstrapping. Bootstrap: The common glue Explaining Bootstrapping can occasionally be missed by many data scientists. However, an understanding of bootstrapping is essential as both the ensemble methods, Boosting and Bagging, are based on the concept of bootstrapping. Figure 1: Bootstrapping In machine learning terms, bootstrap method refers to random sampling with replacement. This sample, after replacement, is referred as a resample. This allows the model or algorithm to get a better understanding of the various biases, variances, and features that exist in the resample. Taking a sample of the data allows the resample to contain different characteristics which the sample might have contained. This would, in turn, affect the overall mean, standard deviation, and other descriptive metrics of a data set. Ultimately, leading to the development of more robust models. The above diagram depicts each sample population having different and non-identical pieces. Bootstrapping is also great for small size data sets that may have a tendency to overfit. In fact, we recommended this to one company who was concerned because their data sets were far from “Big Data”. Bootstrapping can be a solution in this case because algorithms that utilize bootstrapping are more robust and can handle new datasets depending on the methodology chosen (boosting or bagging). The bootstrap method can also test the stability of a solution. By using multiple sample data sets and then testing multiple models, it can increase robustness.  In certain cases, one sample data set may have a larger mean than another or a different standard deviation. This might break a model that was overfitted and not tested using data sets with different variations. One of the many reasons bootstrapping has become so common is because of the increase in computing power. This allows multiple permutations to be done with different resamples. Let us now move on to the most prominent ensemble methods: Bagging and Boosting. Ensemble Method 1: Bagging Bagging actually refers to Bootstrap Aggregators. Most papers or posts that explain bagging algorithms are bound to refer to Leo Breiman’s work, a paper published in 1996 called  “Bagging Predictors”. In the paper, Leo describes bagging as: “Bagging predictors is a method for generating multiple versions of a predictor and using these to get an aggregated predictor.” Bagging helps reduce variance from models that are accurate only on the data they were trained on. This problem is also known as overfitting. Overfitting happens when a function fits the data too well. Typically this is because the actual equation is highly complicated to take into account each data point and the outlier. Figure 2: Overfitting Another example of an algorithm that can overfit easily is a decision tree. The models that are developed using decision trees require very simple heuristics. Decision trees are composed of a set of if-else statements done in a specific order. Thus, if the data set is changed to a new data set that might have some bias or difference in the spread of underlying features compared to the previous set, the model will fail to be as accurate as before. This is because the data will not fit the model well. Bagging gets around the overfitting problem by creating its own variance amongst the data. This is done by sampling and replacing data while it tests multiple hypotheses (models). In turn, this reduces the noise by utilizing multiple samples that would most likely be made up of data with various attributes (median, average, etc). Once each model has developed a hypothesis, the models use voting for classification or averaging for regression. This is where the “Aggregating” of the “Bootstrap Aggregating” comes into play. As in the figure shown below, each hypothesis has the same weight as all the others. (When we later discuss boosting, this is one of the places the two methodologies differ.) Figure 3: Bagging Essentially, all these models run at the same time and vote on the hypothesis which is the most accurate. This helps to decrease variance i.e. reduce the overfit. Ensemble Method 2: Boosting Boosting refers to a group of algorithms that utilize weighted averages to make weak learners into stronger learners. Unlike bagging (that has each model run independently and then aggregate the outputs at the end without preference to any model), boosting is all about “teamwork”. Each model that runs dictates what features the next model will focus on. Boosting also requires bootstrapping. However, there is another difference here. Unlike bagging, boosting weights each sample of data. This means some samples will be run more often than others. Why put weights on the samples of data? Figure 4: Boosting When boosting runs each model, it tracks which data samples are the most successful and which are not. The data sets with the most misclassified outputs are given heavier weights. This is because such data sets are considered to have more complexity. Thus, more iterations would be required to properly train the model. During the actual classification stage, boosting tracks the model's error rates to ensure that better models are given better weights. That way, when the “voting” occurs, like in bagging, the models with better outcomes have a stronger pull on the final output. Which of these ensemble methods is right for me? Ensemble methods generally out-perform a single model. This is why many Kaggle winners have utilized ensemble methodologies. Another important ensemble methodology, not discussed here, is stacking. Boosting and bagging are both great techniques to decrease variance. However, they won’t fix every problem, and they themselves have their own issues. There are different reasons why you would use one over the other. Bagging is great for decreasing variance when a model is overfitted. However, boosting is likely to be a better pick of the two methods. This is because it is also great for decreasing bias in an underfit model. On the other hand, boosting is likely to suffer performance issues. This is where experience and subject matter expertise comes in! It may seem easy to jump on the first model that works. However, it is important to analyze the algorithm and all the features it selects. For instance, a decision tree that sets specific leafs shouldn’t be implemented if it can’t be supported with other data points and visuals. It is not just about trying AdaBoost, or Random forests on various datasets. The final algorithm is driven depending on the results an algorithm is getting and the support provided. [author title="About the Author"] Benjamin Rogojan Ben has spent his career focused on healthcare data. He has focused on developing algorithms to detect fraud, reduce patient readmission and redesign insurance provider policy to help reduce the overall cost of healthcare. He has also helped develop analytics for marketing and IT operations in order to optimize limited resources such as employees and budget. Ben privately consults on data science and engineering problems both solo as well as with a company called Acheron Analytics. He has experience both working hands-on with technical problems as well as helping leadership teams develop strategies to maximize their data.[/author]
Read more
  • 0
  • 0
  • 33954

article-image-keeping-animations-running-at-60-fps-in-a-react-native-app-tutorial
Sugandha Lahoti
15 Mar 2019
4 min read
Save for later

Keeping animations running at 60 FPS in a React Native app [Tutorial]

Sugandha Lahoti
15 Mar 2019
4 min read
An important aspect of any quality mobile app is the fluidity of the user interface. Animations are used to provide a rich user experience, and any jank or jitter can negatively affect this. Animations will likely be used for all kinds of interactions, from changing between views, to reacting to a user's touch interaction on a component. The second most important factor for high-quality animations is to make sure that they do not block the JavaScript thread. To keep animations fluid and not interrupt UI interactions, the render loop has to render each frame in 16.67 ms, so that 60 FPS can be achieved. In this recipe, we will take a look at several techniques for improving the performance of animations in a React Native mobile app. These techniques focus in particular on preventing JavaScript execution from interrupting the main thread. This article is taken from the book React Native Cookbook, Second Edition by Dan Ward.  In this book, you will improve your React Native mobile development skills and learn how to transition from web development to mobile development. For this post, we'll assume that you have a React Native app that has some animations defined. How to do it First and foremost, when debugging animation performance in React Native, we'll want to enable the performance monitor. To do so, show the Dev Menu (shake the device or cmd + D from the simulator) and tap Show Perf Monitor. The output in iOS will look something like the following screenshot: The output in Android will look something like the following screenshot: If you are looking to animate a component's transition (opacity) or dimensions (width, height), then make sure to use LayoutAnimation. If you want to use LayoutAnimation on Android, you need to add the following code when your application starts: UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true). If you need finite control over the animations, it is recommended that you use the Animated library that comes with React Native. This library allows you to offload all of the animation work onto the native UI thread. To do so, we have to add the useNativeDriver property to our Animated call. Let's take a sample Animated example and offload it to the native thread: componentWillMount() { this.setState({ fadeAnimimation: new Animated.Value(0) }); } componentDidMount() { Animated.timing(this.state.fadeAnimimation, { toValue: 1, useNativeDriver: true }).start(); } Currently, only a subset of the functionality of the Animated library supports native offloading. Please refer to the There's more section for a compatibility guide. If you are unable to offload your animation work onto the native thread, there is still a solution for providing a smooth experience. We can use the InteractionManager to execute a task after the animations have completed: componentWillMount() { this.setState({ isAnimationDone: false }); } componentWillUpdate() { LayoutAnimation.easeInAndOut(); } componentDidMount() { InteractionManager.runAfterInteractions(() => { this.setState({ isAnimationDone: true }); }) } render() { if (!this.state.isAnimationDone) { return this.renderPlaceholder(); } return this.renderMainScene(); } Finally, if you are still suffering from poor performance, you'll have to either rethink your animation strategy or implement the poorly performing view as a custom UI view component on the target platform(s). You will have to implement both your view and animation natively using the iOS and/or Android SDK. How it works The tips in this recipe focus on the simple goal of preventing the JavaScript thread from locking. The moment our JavaScript thread begins to drop frames (lock), we lose the ability to interact with our application, even if it's for a fraction of a second. It may seem inconsequential, but the effect is felt immediately by a savvy user. The focus of the tips in this post is to offload animations onto the GPU. When the animation is running on the main thread (the native layer, rendered by the GPU), the user can interact with the app freely without stuttering, hanging, jank, or jitters. There's more Here's a quick reference for where useNativeDriver is usable: Function iOS Android style, value, propertys √ √ decay √ timing √ √ spring √ add √ √ multiply √ √ modulo √ diffClamp √ √ interpoloate √ √ event √ division √ √ transform √ √ If you liked this post, support the author by reading the book React Native Cookbook, Second Edition for enhancing your React Native mobile development skills. React Native 0.59 is now out with React Hooks, updated JavaScriptCore, and more! React Native community announce March updates, post sharing the roadmap for Q4 How to create a native mobile app with React Native [Tutorial]
Read more
  • 0
  • 0
  • 33909

article-image-object-oriented-programming-typescript
Packt
15 Sep 2015
12 min read
Save for later

Writing SOLID JavaScript code with TypeScript

Packt
15 Sep 2015
12 min read
In this article by Remo H. Jansen, author of the book Learning TypeScript, explains that in the early days of software development, developers used to write code with procedural programing languages. In procedural programming languages, the programs follow a top to bottom approach and the logic is wrapped with functions. New styles of computer programming like modular programming or structured programming emerged when developers realized that procedural computer programs could not provide them with the desired level of abstraction, maintainability and reusability. The development community created a series of recommended practices and design patterns to improve the level of abstraction and reusability of procedural programming languages but some of these guidelines required certain level of expertise. In order to facilitate the adherence to these guidelines, a new style of computer programming known as object-oriented programming (OOP) was created. (For more resources related to this topic, see here.) Developers quickly noticed some common OOP mistakes and came up with five rules that every OOP developer should follow to create a system that is easy to maintain and extend over time. These five rules are known as the SOLID principles. SOLID is an acronym introduced by Michael Feathers, which stands for the each following principles: Single responsibility principle (SRP): This principle states that software component (function, class or module) should focus on one unique tasks (have only one responsibility). Open/closed principle (OCP): This principle states that software entities should be designed with the application growth (new code) in mind (be open to extension), but the application growth should require the smaller amount of changes to the existing code as possible (be closed for modification). Liskov substitution principle (LSP): This principle states that we should be able to replace a class in a program with another class as long as both classes implement the same interface. After replacing the class no other changes should be required and the program should continue to work as it did originally. Interface segregation principle (ISP): This principle states that we should split interfaces which are very large (general-purpose interfaces) into smaller and more specific ones (many client-specific interfaces) so that clients will only have to know about the methods that are of interest to them. Dependency inversion principle (DIP): This principle states that entities should depend on abstractions (interfaces) as opposed to depend on concretion (classes). JavaScript does not support interfaces and most developers find its class support (prototypes) not intuitive. This may lead us to think that writing JavaScript code that adheres to the SOLID principles is not possible. However, with TypeScript we can write truly SOLID JavaScript. In this article we will learn how to write TypeScript code that adheres to the SOLID principles so our applications are easy to maintain and extend over time. Let's start by taking a look to interface and classes in TypeScript. Interfaces The feature that we will miss the most when developing large-scale web applications with JavaScript is probably interfaces. Following the SOLID principles can help us to improve the quality of our code and writing good code is a must when working on a large project. The problem is that if we attempt to follow the SOLID principles with JavaScript we will soon realize that without interfaces we will never be able to write truly OOP code that adheres to the SOLID principles. Fortunately for us, TypeScript features interfaces. The Wikipedia's definition of interfaces in OOP is: In object-oriented languages, the term interface is often used to define an abstract type that contains no data or code, but defines behaviors as method signatures. Implementing an interface can be understood as signing a contract. The interface is a contract and when we sign it (implement it) we must follow its rules. The interface rules are the signatures of the methods and properties and we must implement them. Usually in OOP languages, a class can extend another class and implement one or more interfaces. On the other hand, an interface can implement one or more interfaces and cannot extend another class or interfaces. In TypeScript, interfaces doesn't strictly follow this behavior. The main two differences are that in TypeScript: An interface can extend another interface or class. An interface can define data and behavior as opposed to only behavior. An interface in TypeScript can be declared using the interface keyword: interface IPerson { greet(): void; } Classes The support of Classes is another essential feature to write code that adheres to the SOLID principles. We can create classes in JavaScript using prototypes but its is not as trivial as it is in other OOP languages like Java or C#. The ECMAScript 6 (ES6) specification of JavaScript introduces native support for the class keyword but unfortunately ES6 is not compatible with many old browsers that still around. However, TypeScript features classes and allow us to use them today because can indicate to the compiler which version of JavaScript we would like to use (including ES3, ES5, and ES6). Let's start by declaring a simple class: class Person implements Iperson { public name : string; public surname : string; public email : string; constructor(name : string, surname : string, email : string){ this.email = email; this.name = name; this.surname = surname; } greet() { alert("Hi!"); } } var me : Person = new Person("Remo", "Jansen", "remo.jansen@wolksoftware.com"); We use classes to represent the type of an object or entity. A class is composed of a name, attributes, and methods. The class above is named Person and contains three attributes or properties (name, surname, and email) and two methods (constructor and greet). The class attributes are used to describe the objects characteristics while the class methods are used to describe its behavior. The class above uses the implements keyword to implement the IPerson interface. All the methods (greet) declared by the IPerson interface must be implemented by the Person class. A constructor is an especial method used by the new keyword to create instances (also known as objects) of our class. We have declared a variable named me, which holds an instance of the class Person. The new keyword uses the Person class's constructor to return an object which type is Person. Single Responsibility Principle This principle states that a software component (usually a class) should adhere to the Single Responsibility Principle (SRP). The Person class above represents a person including all its characteristics (attributes) and behaviors (methods). Now, let's add some email is validation logic to showcase the advantages of the SRP: class Person { public name : string; public surname : string; public email : string; constructor(name : string, surname : string, email : string) { this.surname = surname; this.name = name; if(this.validateEmail(email)) { this.email = email; } else { throw new Error("Invalid email!"); } } validateEmail() { var re = /S+@S+.S+/; return re.test(this.email); } greet() { alert("Hi! I'm " + this.name + ". You can reach me at " + this.email); } } When an object doesn't follow the SRP and it knows too much (has too many properties) or does too much (has too many methods) we say that the object is a God object. The preceding class Person is a God object because we have added a method named validateEmail that is not really related to the Person class behavior. Deciding which attributes and methods should or should not be part of a class is a relatively subjective decision. If we spend some time analyzing our options we should be able to find a way to improve the design of our classes. We can refactor the Person class by declaring an Email class, which is responsible for the e-mail validation and use it as an attribute in the Person class: class Email { public email : string; constructor(email : string){ if(this.validateEmail(email)) { this.email = email; } else { throw new Error("Invalid email!"); } } validateEmail(email : string) { var re = /S+@S+.S+/; return re.test(email); } } Now that we have an Email class we can remove the responsibility of validating the e-mails from the Person class and update its email attribute to use the type Email instead of string. class Person { public name : string; public surname : string; public email : Email; constructor(name : string, surname : string, email : Email){ this.email = email; this.name = name; this.surname = surname; } greet() { alert("Hi!"); } } Making sure that a class has a single responsibility makes it easier to see what it does and how we can extend/improve it. We can further improve our Person an Email classes by increasing the level of abstraction of our classes. For example, when we use the Email class we don't really need to be aware of the existence of validateEmail method so this method could be private or internal (invisible from the outside of the Email class). As a result, the Email class would be much simpler to understand. When we increase the level of abstraction of an object, we can say that we are encapsulating that object. Encapsulation is also known as information hiding. For example, in the Email class allow us to use e-mails without having to worry about the e-mail validation because the class will deal with it for us. We can make this more clearly by using access modifiers (public or private) to flag as private all the class attributes and methods that we want to abstract from the usage of the Email class: class Email { private email : string; constructor(email : string){ if(this.validateEmail(email)) { this.email = email; } else { throw new Error("Invalid email!"); } } private validateEmail(email : string) { var re = /S+@S+.S+/; return re.test(email); } get():string { return this.email; } } We can then simply use the Email class without explicitly perform any kind of validation: var email = new Email("remo.jansen@wolksoftware.com"); Liskov Substitution Principle Liskov Substitution Principle (LSP) states: Subtypes must be substitutable for their base types. Let's take a look at an example to understand what this means. We are going to declare a class which responsibility is to persist some objects into some kind of storage. We will start by declaring the following interface: interface IPersistanceService { save(entity : any) : number; } After declaring the IPersistanceService interface we can implement it. We will use cookies the storage for the application's data: class CookiePersitanceService implements IPersistanceService{ save(entity : any) : number { var id = Math.floor((Math.random() * 100) + 1); // Cookie persistance logic... return id; } } We will continue by declaring a class named FavouritesController, which has a dependency on the IPersistanceService interface: class FavouritesController { private _persistanceService : IPersistanceService; constructor(persistanceService : IPersistanceService) { this._persistanceService = persistanceService; } public saveAsFavourite(articleId : number) { return this._persistanceService.save(articleId); } } We can finally create and instance of FavouritesController and pass an instance of CookiePersitanceService via its constructor. var favController = new FavouritesController(new CookiePersitanceService()); The LSP allows us to replace a dependency with another implementation as long as both implementations are based in the same base type. For example, we decide to stop using cookies as storage and use the HTML5 local storage API instead without having to worry about the FavouritesController code being affected by this change: class LocalStoragePersitanceService implements IpersistanceService { save(entity : any) : number { var id = Math.floor((Math.random() * 100) + 1); // Local storage persistance logic... return id; } } We can then replace it without having to add any changes to the FavouritesController controller class: var favController = new FavouritesController(new LocalStoragePersitanceService()); Interface Segregation Principle In the previous example, our interface was IPersistanceService and it was implemented by the cases LocalStoragePersitanceService and CookiePersitanceService. The interface was consumed by the class FavouritesController so we say that this class is a client of the IPersistanceService API. Interface Segregation Principle (ISP) states that no client should be forced to depend on methods it does not use. To adhere to the ISP we need to keep in mind that when we declare the API (how two or more software components cooperate and exchange information with each other) of our application's components the declaration of many client-specific interfaces is better than the declaration of one general-purpose interface. Let's take a look at an example. If we are designing an API to control all the elements in a vehicle (engine, radio, heating, navigation, lights, and so on) we could have one general-purpose interface, which allows controlling every single element of the vehicle: interface IVehicle { getSpeed() : number; getVehicleType: string; isTaxPayed() : boolean; isLightsOn() : boolean; isLightsOff() : boolean; startEngine() : void; acelerate() : number; stopEngine() : void; startRadio() : void; playCd : void; stopRadio() : void; } If a class has a dependency (client) in the IVehicle interface but it only wants to use the radio methods we would be facing a violation of the ISP because, as we have already learned, no client should be forced to depend on methods it does not use. The solution is to split the IVehicle interface into many client-specific interfaces so our class can adhere to the ISP by depending only on Iradio: interface IVehicle { getSpeed() : number; getVehicleType: string; isTaxPayed() : boolean; isLightsOn() : boolean; } interface ILights { isLightsOn() : boolean; isLightsOff() : boolean; } interface IRadio { startRadio() : void; playCd : void; stopRadio() : void; } interface IEngine { startEngine() : void; acelerate() : number; stopEngine() : void; } Dependency Inversion Principle Dependency Inversion (DI) principle states that we should: Depend upon Abstractions. Do not depend upon concretions In the previous section, we implemented FavouritesController and we were able to replace an implementation of IPersistanceService with another without having to perform any additional change to FavouritesController. This was possible because we followed the DI principle as FavouritesController has a dependency on the IPersistanceService interface (abstractions) rather than LocalStoragePersitanceService class or CookiePersitanceService class (concretions). The DI principle also allow us to use an inversion of control (IoC) container. An IoC container is a tool used to reduce the coupling between the components of an application. Refer to Inversion of Control Containers and the Dependency Injection pattern by Martin Fowler at http://martinfowler.com/articles/injection.html. If you want to learn more about IoC. Summary In this article, we looked upon classes, interfaces, and the SOLID principles. Resources for Article: Further resources on this subject: Welcome to JavaScript in the full stack [article] Introduction to Spring Web Application in No Time [article] Introduction to TypeScript [article]
Read more
  • 0
  • 0
  • 33906
article-image-getting-started-jupyter-notebook-part-1
Marin Gilles
02 Feb 2016
5 min read
Save for later

Getting started with the Jupyter notebook (part 1)

Marin Gilles
02 Feb 2016
5 min read
The Jupyter notebook (previously known as IPython notebooks) is an interactive notebook, in which you can run code from more than 40 programming languages. In this introduction, we will explore the main features of the Jupyter notebook and see why it can be such a poweful tool for anyone wanting to create beautiful interactive documents and educational resources. To start this working with the notebook, you will need to install it. You can find the full procedure on the Jupyter website. jupyter notebook You will see something similar to the following displayed : [I 20:06:36.367 NotebookApp] Writing notebook server cookie secret to /run/user/1000/jupyter/notebook_cookie_secret [I 20:06:36.813 NotebookApp] Serving notebooks from local directory: /home/your_username [I 20:06:36.813 NotebookApp] 0 active kernels [I 20:06:36.813 NotebookApp] The IPython Notebook is running at: http://localhost:8888/ [I 20:06:36.813 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation). And the main Jupyter window should open in the folder you started the notebook (usually your user folder). The main window looks like this : To create a new notebook, simply click on New and choose the kind of notebook you wish to start under the notebooks section. I only have a Python kernel installed locally, so I will start a Python notebook to start working with. A new tab opens, and I get the notebook interface, completely empty. You can see different parts of the notebook: Name of your notebook Main toolbar, with options to save your notebook, export, reload, un notebook[RB1] , restart kernel, etc. Shortcuts The main part of the notebook, containing the contents of your notebook Take the time to explore the menus and see your options. If you need help on a very specific subject, concerning the notebook or some libraries, you can try the help menu at the right end of the menu bar. In the main area, you can see what is called a cell. Each notebook is composed of multiple cells, and each cell will be used for a different purpose. The first cell we have here, starting with In [ ] is a code cell. In this type of cell, you can type any code and execute it. For example, try typing 1 + 2 then hit Shift + Enter. When hitting Shift + Enter, the code in the cell will be evaluated, you will be placed in a new cell, and you will get the following: You can easily identify the current working cell thanks to the green outline. Let's type something else in the second cell, for example: for i in range(5): print(i) When evaluating this cell, you then get: As previously, the code is evaluated and the results are dislayed properly. You may notice there is no Out[2] this time. This is because we printed the results, and no value was returned. One very interesting feature of the notebook is that you can go back in a cell, change it and reevaluate it again, thus updating your whole document. Try this by going back to the first cell, changing 1 + 2 to 2 + 3, and reevaulating the cell, by pressing Shift + Enter. You will notice the result was updated to 5 as soon as you evaluated the cell. This can be very powerful when you want to explore data or test an equation with different parameters without having to reevaluate your whole script. You can, however, reevaluate the whole notebook at once, by going to Cell -> Run all. Now that we’ve seen how to enter code, why not try and get a more beautiful and explanatory notebook? To do this, we will use other types of cells, the Header and Markdown cells. First, let's add a title to our notebook at the very top. To do that, select the first cell, then click Insert -> Insert cell above. As you can see, a new cell was added at the very top of your document. However, this looks exactly like the previous one. Let's make it a title cell by clicking on the cell type menu, in the shortcut toolbar: You then change it to Heading. A pop-up will be displayed explaining how to create different levels of titles, and you will be left with a different type of cell: This cell starts with a # sign, meaning this is a level one title. If you want to make subtitles, you can just use the following notation (explained in the pop-up showing up when changing the cell type): # : First level title ## : Second level title ### : Third level title ... Write your title after the #, then evaluate the cell. You will see the display changing to show a very nice looking title. I added a few other title cells as an example, and an exercise for you: After adding our titles, let's add a few explanations about what we do in each code cell. For this, we will add a cell where we want it to be, and then change its type to Markdown. Then, evaluate your cell. That's it: your text is displayed beautifully! To finish this first introduction, you can rename your notebook by going to File -> Rename and inputing the new name of your notebook. It will then be displayed on the top left of your window, next to the Jupyter logo. In the next part of this introduction, we will go deeper in the capabilities of the notebook and the integration with other Python libraries. Click here to carry on reading now! About the author Marin Gilles is a PhD student in Physics, in Dijon, France. A large part of his work is dedicated to physical simulations for which he developed his own simulation framework using Python, and contributed to open-source libraries such as Matplotlib or IPython.
Read more
  • 0
  • 0
  • 33905

article-image-how-to-do-data-storytelling-well-with-tableau-video
Sugandha Lahoti
13 Oct 2018
2 min read
Save for later

How to do data storytelling well with Tableau [Video]

Sugandha Lahoti
13 Oct 2018
2 min read
Data tells you what is happening, but stories tell you why it matters. Tableau story points and dashboards are useful features in Tableau that are helping to drive an evolution in data storytelling. This clip is taken from the video Tableau Data Stories for Everyone by Fabio Fierro. https://www.youtube.com/watch?v=oqV0juvO5og The challenge of data storytelling The challenge for a ‘data storyteller’ is to act as a bridge between raw data, insights, and the world outside them where those insights actually matter and can have an impact on decision making. By intelligently plotting data in a way that’s both clear and engaging, you can help stakeholders - whether that’s senior management or customers - better understand the context of your data and appreciate the connections you are trying to draw in your analytical work. There are a number of different data storytelling techniques you can use when working with Tableau to more effectively communicate with your audience. These include: Looking at changes over time Drilling down into interesting details of your analysis Zooming out to show a broad view on what your analysis might show The contrast shows to highlight interesting points of difference that could be useful for your audience Intersections highlight important shifts when one category overtakes other. Factors explain a subject by dividing it into types or categories and discussing if a subcategory needs to be focused on more. Outliers display anomalies which are exceptionally different. Watch the clip above to learn more about how you can use Tableau for incredible data storytelling. About the author Fabio Fierro is a Chief consultant of a group of Tableau experts and storytellers. He has several years’ experience in delivering end-to-end business intelligence solution within the corporate world. As a business analyst, he enjoys creating innovative solutions to analyze any kind of data. Announcing Tableau Prep 2018.2.1! A tale of two tools: Tableau and Power BI Visualizing BigQuery Data with Tableau.
Read more
  • 0
  • 0
  • 33871