If enabled, will allow users the ability to click and drag anywhere on the grid to select a range of cells. Having this option enabled prevents you from using the browser's default text selection methods.
Note: This option cannot be toggled via grid.setOptions()
. It must be set at initialization.
(boolean)
: Defaulttrue
.
{selectable: false}


|
Cheetah API
|
Functions | |
| def | get_adios_version (xml_file) |
| def | set_engine (xmlfile, io_obj, engine_type, parameters=None) |
| def | set_transport (xmlfile, io_obj, transport_type, parameters=None) |
| def | set_var_operation (xmlfile, io_obj, var_name, operation, parameters=None) |
ADIOS2 Interface
| def codar.cheetah.adios2_interface.get_adios_version | ( | xml_file | ) |
Get the ADIOS version of this xml file. :param xml_file: Path to the adios xml file :return: 1 (adios version 1) or 2 (adios version 2)
Definition at line 32 of file adios2_interface.py.
| def codar.cheetah.adios2_interface.set_engine | ( | xmlfile, | |
| io_obj, | |||
| engine_type, | |||
parameters = None |
|||
| ) |
Set the engine type for an input IO object. :param xmlfile: String. The ADIOS2 xml file to be modified :param io_obj: String. Name of the io object which contains the engine :param engine_type: String. The engine type to be set for the io object :param parameters: List. A list of dicts containing 'key and 'value' keys :return: True on success, False on error
Definition at line 51 of file adios2_interface.py.
| def codar.cheetah.adios2_interface.set_transport | ( | xmlfile, | |
| io_obj, | |||
| transport_type, | |||
parameters = None |
|||
| ) |
Set the transport type for an io object :param xmlfile: String. The ADIOS2 xml file to be modified :param io_obj: String. Name of the io object that contains the engine :param transport_type String. The transport type for this io object :param parameters: A dict containing the parameter keys and values :return: True on success, False on error
Definition at line 76 of file adios2_interface.py.
| def codar.cheetah.adios2_interface.set_var_operation | ( | xmlfile, | |
| io_obj, | |||
| var_name, | |||
| operation, | |||
parameters = None |
|||
| ) |
Set an operation on a variable :param xmlfile: String. The ADIOS2 xml file to be modified :param io_obj: String. Name of the io object that contains the engine :param var_name String. Name of the variable :param operation String. The operation to be performed on the variable :param parameters: A dict containing the parameter keys and values :return: True on success, False on error
Definition at line 100 of file adios2_interface.py.


{% extends 'base.html' %} {% load markdown_deux_tags %} {% load static %} {% block content %} {% if not questions_html %}
You can start adding/updating questions to your quiz by clicking on the Edit button.
You should also make sure that you set the
settings for the quiz correctly before hitting Publish!
After you are done with creating the quiz, goto Publish page.
NoteYou might also be required to click Publish button on the Studio (LTI Consumer) for this Unit to make the quiz live and running!
Please note that you will not be able to edit the questions of the quiz if any students attempts the quiz! So make sure that you are done with the quiz before publishing it!
The duration of this quiz is {{duration}} minutes.
There is NO time limit on this quiz.
The maximum number of allowed attempt for this quiz is {{max_attempt}}
There is NO limit on the number of attempts. Note that only the latest attempt's responses are saved in the database in this particular case. If the quiz is again attempted by the student, then the last attempt's record is overriden!.
There are total {{total_questions_number}} questions in this quiz.


@(execution: ExecutionView)(implicit flash: Flash, globalViewContext: GlobalViewContext) @main("Test Execution", "Execution") {
| Name | @execution.name.full |
| Group | @group.full |
| Batch | @execution.batchName |
| Summary | @summary.full |
| Date | @execution.executionTime.absolute (@execution.executionTime.relative) |
| Duration | @duration |
| Configuration | @execution.configuration |
| Comment | @for(comment <- execution.commentOpt) { @comment } edit |
@log} @editComment(execution.commentOpt, routes.ExecutionController.setExecutionComment(execution.id)) }


IRI: http://www.w3id.org/def/irrig#AmountProperty
IRI: http://www.w3id.org/def/irrig#CropGrowthDeduction
A CropGrowthDeduction is made by the Software_agent Sensor based on human observation
IRI: http://www.w3id.org/def/irrig#CropGrowthObservation
A CropGrowthObservation that made by the CatherineRoussey Sensor (human observation or biology sensor).
IRI: http://www.w3id.org/def/irrig#CropGrowthState
A State V2 is linked to an individual of CropGrowth Property dedicated to maize crop. The V2 State is reached when two leaves are fully emerged with collars visible in a maize plant. The State appearance could be evaluated by human observation or by automatic method like the Growing Degree Unit (GDU).
IRI: http://www.w3id.org/def/irrig#CropWaterNeedDeduction
A CropWaterNeedDeduction that made by the Software_agent Sensor based on observations made by tensiometer sensor
IRI: http://www.w3id.org/def/irrig#CropWaterNeedState
Example: The State No of the CropWaterNeed Property represents the fact that the crop does not need water. The State Yes of the CropWaterNeed Property represents the fact that the crop needs extra water.
IRI: http://www.w3id.org/def/irrig#DelayDurationObservation
IRI: http://www.w3id.org/def/irrig#GrowthProperty
CropGrowth is a GrowthProperty representing the physical development of crop.
IRI: http://www.w3id.org/def/irrig#IntensityProperty
RainIntensity is a IntensityProperty representing the strength effect of rain.
IRI: http://www.w3id.org/def/irrig#IrrigationActuation
An IrrigationActuation is made by Watering Valve Actuator, links to Soil30cmDepth FeatureOfInterest and its Soil30cmDepthMoisture ActuatableProperty.
IRI: http://www.w3id.org/def/irrig#MoistureProperty
RootZoneMoistureLevel is a MoistureProperty representing the amount of water available around the soil’s root zone area of a plant.
IRI: https://w3id.org/def/saref4agri#Pluviometer
IRI: http://www.w3id.org/def/irrig#RainDailyTotalQuantityObservation
A RainDailyTotalQuantityObservation is computed by the SoftwareAgent Sensor based on observations made by a pluviometer.
IRI: http://www.w3id.org/def/irrig#RainIntensityBoundary
10 mm is the value of the Quantity_low Boundary that distinguish the Light State from the Moderate State of the RainIntensity Property.
IRI: http://www.w3id.org/def/irrig#RainIntensityDeduction
A RainIntensityDeduction that made by the Software_agent Sensor based on observations made by a pluviometer sensor
IRI: http://www.w3id.org/def/irrig#RainIntensityState
Example: The State Light of the RainIntensity Property represents a fact that there is no enought rain to take any decision about irrigation.
IRI: http://www.w3id.org/def/irrig#RainQuantityObservation
A RainQuantityObservation that made by the Pluviometer Sensor.
IRI: http://www.w3id.org/def/irrig#RootZoneDailyAverageMoistureObservation
A RootZoneDailyAverageMoistureObservation is computed by the SoftwareAgent Sensor.
IRI: http://www.w3id.org/def/irrig#RootZoneMoistureLevelBoundary
10 cbar is the value of the Tension_veryHigh Boundary that distinguish the Saturated State from the VeryHigh State of the RootZoneMoistureLevel Property.
IRI: http://www.w3id.org/def/irrig#RootZoneMoistureLevelDeduction
A RootZoneMoistureLevelDeduction that made by the Software_agent.
IRI: http://www.w3id.org/def/irrig#RootZoneMoistureLevelState
The State Saturated of the RootZoneMoistureLevel Property represents a fact that the moisture in rootzone is saturated in water.
IRI: http://www.w3id.org/def/irrig#SleepingDurationObservation
IRI: http://www.w3id.org/def/irrig#Soil30cmDepthDailyAverageMoistureObservation
A Soil30cmDepthDailyAverageMoistureObservation is computed by the SoftwareAgent Sensor.
IRI: http://www.w3id.org/def/irrig#Soil30cmDepthMoistureObservation
A Soil30cmDepthMoistureObservation is made by the SoilTensiometer_01 Sensor placed at 30 cm depth in the soil.
IRI: http://www.w3id.org/def/irrig#Soil60cmDepthDailyAverageMoistureObservation
A Soil60cmDepthAverageDailyMoistureObservation ismade by the SoftwareAgent Sensor.
IRI: http://www.w3id.org/def/irrig#Soil60cmDepthMoistureObservation
A Soil60cmDepthMoistureObservation is made by the Tensiometer Sensor placed at 60 cm depth in the soil.
IRI: https://w3id.org/def/saref4agri#SoilTensiometer
IRI: http://www.w3id.org/def/irrig#StressProperty
CropWaterNeed is a StressProperty representing the stress inside the plant when it needs extra water. It corresponds to the drought stress.


Recently, my friend and roomate challenged me to a competition of sorts. Homemade absinthe, who could come up with the best recipe through the standard process of trial and error? So several batches later, I have come up with a collection of flavors which I think works best.
Keep in mind the primary purpose of making absinthe was to capture the active ingredients in an alcohol extraction, not a difficult process in itself. Anyone who has gone this far knows what the next problem encountered is. 'What in the name of all that's good and holy can I do to get rid of that taste?' So from that point my efforts mainly centered on what I could do to keep each area of my tongue from experiencing the vile and putrid bitterness of the wormwood. So here are the major components in my recipe. I try to avoid any strict formula for ratios and amounts, as I believe that the individual should have the pleasure of finding their own perfect balance. If you really need exact numbers though, read some other recipes out their and grab some measurements. To be nice though, I grouped the ingredients roughly by the amount and/or step during which they should be used.
So, here we go: Just remember, if an ingredient can be made into smaller pieces, why not?
Procure a gallon jug and insert:
Wormwood (enough to cover 3/4 to 1/2 inch at the bottom of the jug while fluffy)
Licorice Root (10-15 sticks, but more than the wormwood)
Cardamom Seeds (10-15 pods worth)
750 ml of 152 proof neutral grain spirits
1 liter of cheap 80 proof vodka
Leave this in a warm dark place for three days, periodically shaking and admiring.
then add to the mixture
somewhere between .5 and 2.0 tablespoons each of:
Angelica root
Corriander seed
Anise seed
Fennel seed
Whole Cloves
Black and White Peppercorns
Lavender (4 tbsp.)
1/2 Whole Vanilla Bean
a little more wormwood
some lemon peel
a pinch of Blue Green Algae (for color and vitamins)
1 small ginseng root (unless your yang is fine where it is.)
and let the mixture sit for the remainder of the week in a warm dark place. Once again periodically removing it from hiding to agitate, carress, coo, and speak fond words to it.
At the end of the week remove it and filter and re-filter the liquid from the solid materials (I've never been able to eliminate all of the sediment) Save the vanilla bean if you can because it looks nice at the bottom of the bottle. So once you have decanted and filtered your way down to as clear a liquid as you can imagine getting, take those three empty bottles, the ones I hadn't mentioned yet. Find three bottles each holding about 750 ml, empty and wash them and as the final stage begins, add about a half a cup of honey to two of the bottles while they are still empty, and a quarter cup to the third. Using your bar funnel, pour the liquid into the bottles according to their amounts of honey and seal them up. Then shake each bottle vigorously to mix the honey with the liquor.
By the time you finish, the proof should be between 100 and 110 and you should have a quite servicable Absinthe liquer. As I said, almost every ingredient is to cover some part of the wormwood, either in the nose or the tongue. So the true flavor and aroma doesn't become apparant until after you've had the first shot.
This recipe is about a month old, and I've drank maybe a liter and a half in that time. The only notable side effects I'm having are a certain amount of listlessness the next morning that I don't always associate with alchohol. Beyond that, I can tell there's a little something else that my body has to filter out, but it's barely different from alchohol.
The effect: I personally don't find the effect to be noticably different than alchohol until the fifth serving or so. Granted, the alchohol content is stronger than most. If I had to identify the feeling precisely, I would say that I feel some of somatic and kinesthetic displacement which I used to associate with dextramethorophan. Other than that it's like drinking liquor.
Helpful tips: For extra fun, throw 1/8 oz. each of mariajuana and cubensis into the original mixing. not enough to take over the drink, but definitely a kick in the spine after a few rounds.
Also: I've found the best mixers, besides the traditional method, are lemonade and a nice dry hard cider.
have fun!
imp
I'd also like to thank Anthony, who will kick my ass if I don't mention him.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


I am a penultimate Computer Engineering student at the National
University of Singapore aspiring to deepen my understanding and
gain insights in the technology industry, with a particular
interest in software as tools to improve the lives of many.
As someone who has always been fascinated by the amazing feats
technology help us achieve, I am constantly exploring different
fields of computer technology. From software engineering to data
analytics, I am always in pursuit of opportunities to not only
expand my skill set, but also bring about change to the world we
live in.
Tech Stack: Python, SQL, Apache Spark
Shopee is Southeast Asia’s largest e-commerce platform, operating in
7 countries across the region
Performed key exploratory analyses on large-scale fraud cases using
Python & SQL, of which the results were presented by the team to
Shopee’s CEO
Significantly reduce the frequency of a variety of fraud cases
happening in Shopee’s regional markets by formulating SQL rules to
aid in the suspension of fraudulent users
Reduced the team’s operational overhead through workflow automation
and orchestration
Tech Stack: Go, Python, SQL, Apache Airflow, Google Cloud Platform
Gojek is one of Southeast Asia’s largest ride-hailing apps, having
also expanded to industries such as food delivery, fintech &
logistics. Gojek is aspiring to become the ‘super-app’ of the region
Worked in close collaboration with the Data Science & Analytics team
to build data pipelines that can handle hundreds of gigabytes daily
to prevent and detect fraudulent activities on Gojek’s platforms
Improved the team’s applications’ reliability and testing coverage
by writing integration tests and setting up environments to allow
software tests on mock Apache Kafka clusters
The Computer Engineering program puts emphasis on understanding
computers through the lenses of both an Electrical Engineer and a
Computer Scientist. The computer engineering curriculum at NUS teaches
students how the intermarriage between software and hardware creates
smart & reliable computer systems as tools and enablers in the modern
digital era.
Relevant Courses: Software Engineering, Data Structures & Algorithms,
Real-Time Operating Systems, Database Systems, Machine Learning,
Computer Vision, Programming Methodology, etc.
Alongside a team of NUS Computer Engineering students, built a prototype search and rescue robot that could be controlled remotely through Wi-Fi and navigated using Simultaneous Localization and Mapping (SLAM). In this project, I was responsible for setting up, calibrating and writing the firmware for the robot's sensors
View ProjectAs part of the Software Engineering course in NUS, built a simple application for users to manage personal events using Java and JavaFX. I was responsible for building the log in and sign up feature for this application
View Project


|
|
|
|
|
|
|
|
|
Team Totals
|
2018-19 |
2019-20 |
2020-21 |
2021-22 |
2022-23 |
2023-24 |
|
|
|
|
|
|
|
|
|
|
Original Salary
|
130,002,842 |
130,002,842 |
130,002,842 |
130,002,842 |
|
|
|
Salary
|
130,002,842 |
130,002,842 |
130,002,842 |
130,002,842 |
|
|
|
New Salary
|
130,002,842 |
130,002,842 |
130,002,842 |
130,002,842 |
|
|
|
|
|
|
|
|
|
|
|
|
Total Contracts
|
10 |
14 |
6 |
2 |
|
|
|
1st Round Picks
|
|
1 |
2 |
2 |
3 |
3 |
|
1st Round Pick's Salary
|
|
130,002,842 |
130,002,842 |
130,002,842 |
130,002,842 |
130,002,842 |
|
Cap Hold
|
|
130,002,842 |
130,002,842 |
130,002,842 |
130,002,842 |
130,002,842 |
|
Cap
|
130,002,842 |
130,002,842 |
130,002,842 |
130,002,842 |
130,002,842 |
130,002,842 |
|
New Cap Room
|
130,002,842 |
130,002,842 |
130,002,842 |
130,002,842 |
|
|
|
|
|
|
|
|
|
|
|
|
Tax
|
(435,343) |
1,422 |
|
|
|
|
|
Tax Limit
|
|
1 |
2 |
2 |
3 |
3 |
|
Tax Adjustment
|
|
130,002,842 |
130,002,842 |
130,002,842 |
130,002,842 |
130,002,842 |
|
New Tax Room
|
130,002,842 |
130,002,842 |
130,002,842 |
130,002,842 |
|
|
|
|
|
|
|
|
Exceptions
|
| $8,250,446 |
ML |
REM: 8,250,446 |
| $8,250,446 |
BA |
REM: 8,250,446 |
| $8,250,446 |
TR |
Exp: 02/08/19 |
|
|
|
|
|
Draft Picks
|
| Year |
Round 1 |
Round 2 |
| 2019 |
OWN (9) |
|
| 2020 |
OWN (9) |
|
| 2021 |
|
|
| 2022 |
OWN (9) |
OWN (39) |
| 2023 |
OWN (9) |
|
| 2024 |
OWN (9) |
OWN? |
| 2025 |
OWN (9) |
OWN (39) |
|


(beta) Dynamic Quantization on BERT¶
Tip
To get the most of this tutorial, we suggest using this Colab Version. This will allow you to experiment with the information presented below.
Author: Jianyu Huang
Reviewed by: Raghuraman Krishnamoorthi
Edited by: Jessica Lin
Introduction¶
In this tutorial, we will apply the dynamic quantization on a BERT model, closely following the BERT model from the HuggingFace Transformers examples. With this step-by-step journey, we would like to demonstrate how to convert a well-known state-of-the-art model like BERT into dynamic quantized model.
BERT, or Bidirectional Embedding Representations from Transformers, is a new method of pre-training language representations which achieves the state-of-the-art accuracy results on many popular Natural Language Processing (NLP) tasks, such as question answering, text classification, and others. The original paper can be found here.
Dynamic quantization support in PyTorch converts a float model to a quantized model with static int8 or float16 data types for the weights and dynamic quantization for the activations. The activations are quantized dynamically (per batch) to int8 when the weights are quantized to int8. In PyTorch, we have torch.quantization.quantize_dynamic API, which replaces specified modules with dynamic weight-only quantized versions and output the quantized model.
We demonstrate the accuracy and inference performance results on the Microsoft Research Paraphrase Corpus (MRPC) task in the General Language Understanding Evaluation benchmark (GLUE). The MRPC (Dolan and Brockett, 2005) is a corpus of sentence pairs automatically extracted from online news sources, with human annotations of whether the sentences in the pair are semantically equivalent. As the classes are imbalanced (68% positive, 32% negative), we follow the common practice and report F1 score. MRPC is a common NLP task for language pair classification, as shown below.
1. Setup¶
1.1 Install PyTorch and HuggingFace Transformers¶
To start this tutorial, let’s first follow the installation instructions in PyTorch here and HuggingFace Github Repo here. In addition, we also install scikit-learn package, as we will reuse its built-in F1 score calculation helper function.
pip install sklearn
pip install transformers
Because we will be using the beta parts of the PyTorch, it is recommended to install the latest version of torch and torchvision. You can find the most recent instructions on local installation here. For example, to install on Mac:
yes y | pip uninstall torch tochvision
yes y | pip install --pre torch -f https://download.pytorch.org/whl/nightly/cu101/torch_nightly.html
1.2 Import the necessary modules¶
In this step we import the necessary Python modules for the tutorial.
from __future__ import absolute_import, division, print_function
import logging
import numpy as np
import os
import random
import sys
import time
import torch
from argparse import Namespace
from torch.utils.data import (DataLoader, RandomSampler, SequentialSampler,
TensorDataset)
from tqdm import tqdm
from transformers import (BertConfig, BertForSequenceClassification, BertTokenizer,)
from transformers import glue_compute_metrics as compute_metrics
from transformers import glue_output_modes as output_modes
from transformers import glue_processors as processors
from transformers import glue_convert_examples_to_features as convert_examples_to_features
# Setup logging
logger = logging.getLogger(__name__)
logging.basicConfig(format = '%(asctime)s - %(levelname)s - %(name)s - %(message)s',
datefmt = '%m/%d/%Y %H:%M:%S',
level = logging.WARN)
logging.getLogger("transformers.modeling_utils").setLevel(
logging.WARN) # Reduce logging
print(torch.__version__)
We set the number of threads to compare the single thread performance between FP32 and INT8 performance. In the end of the tutorial, the user can set other number of threads by building PyTorch with right parallel backend.
torch.set_num_threads(1)
print(torch.__config__.parallel_info())
1.3 Learn about helper functions¶
The helper functions are built-in in transformers library. We mainly use the following helper functions: one for converting the text examples into the feature vectors; The other one for measuring the F1 score of the predicted result.
The glue_convert_examples_to_features function converts the texts into input features:
Tokenize the input sequences;
Insert [CLS] in the beginning;
Insert [SEP] between the first sentence and the second sentence, and in the end;
Generate token type ids to indicate whether a token belongs to the first sequence or the second sequence.
The glue_compute_metrics function has the compute metrics with the F1 score, which can be interpreted as a weighted average of the precision and recall, where an F1 score reaches its best value at 1 and worst score at 0. The relative contribution of precision and recall to the F1 score are equal.
The equation for the F1 score is:
1.4 Download the dataset¶
Before running MRPC tasks we download the GLUE data by running this script
and unpack it to a directory glue_data
.
python download_glue_data.py --data_dir='glue_data' --tasks='MRPC'
2. Fine-tune the BERT model¶
The spirit of BERT is to pre-train the language representations and then to fine-tune the deep bi-directional representations on a wide range of tasks with minimal task-dependent parameters, and achieves state-of-the-art results. In this tutorial, we will focus on fine-tuning with the pre-trained BERT model to classify semantically equivalent sentence pairs on MRPC task.
To fine-tune the pre-trained BERT model (bert-base-uncased
model in
HuggingFace transformers) for the MRPC task, you can follow the command
in examples:
export GLUE_DIR=./glue_data
export TASK_NAME=MRPC
export OUT_DIR=./$TASK_NAME/
python ./run_glue.py \
--model_type bert \
--model_name_or_path bert-base-uncased \
--task_name $TASK_NAME \
--do_train \
--do_eval \
--do_lower_case \
--data_dir $GLUE_DIR/$TASK_NAME \
--max_seq_length 128 \
--per_gpu_eval_batch_size=8 \
--per_gpu_train_batch_size=8 \
--learning_rate 2e-5 \
--num_train_epochs 3.0 \
--save_steps 100000 \
--output_dir $OUT_DIR
We provide the fined-tuned BERT model for MRPC task here.
To save time, you can download the model file (~400 MB) directly into your local folder $OUT_DIR
.
2.1 Set global configurations¶
Here we set the global configurations for evaluating the fine-tuned BERT model before and after the dynamic quantization.
configs = Namespace()
# The output directory for the fine-tuned model, $OUT_DIR.
configs.output_dir = "./MRPC/"
# The data directory for the MRPC task in the GLUE benchmark, $GLUE_DIR/$TASK_NAME.
configs.data_dir = "./glue_data/MRPC"
# The model name or path for the pre-trained model.
configs.model_name_or_path = "bert-base-uncased"
# The maximum length of an input sequence
configs.max_seq_length = 128
# Prepare GLUE task.
configs.task_name = "MRPC".lower()
configs.processor = processors[configs.task_name]()
configs.output_mode = output_modes[configs.task_name]
configs.label_list = configs.processor.get_labels()
configs.model_type = "bert".lower()
configs.do_lower_case = True
# Set the device, batch size, topology, and caching flags.
configs.device = "cpu"
configs.per_gpu_eval_batch_size = 8
configs.n_gpu = 0
configs.local_rank = -1
configs.overwrite_cache = False
# Set random seed for reproducibility.
def set_seed(seed):
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
set_seed(42)
2.2 Load the fine-tuned BERT model¶
We load the tokenizer and fine-tuned BERT sequence classifier model
(FP32) from the configs.output_dir
.
tokenizer = BertTokenizer.from_pretrained(
configs.output_dir, do_lower_case=configs.do_lower_case)
model = BertForSequenceClassification.from_pretrained(configs.output_dir)
model.to(configs.device)
2.3 Define the tokenize and evaluation function¶
We reuse the tokenize and evaluation function from Huggingface.
# coding=utf-8
# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team.
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
def evaluate(args, model, tokenizer, prefix=""):
# Loop to handle MNLI double evaluation (matched, mis-matched)
eval_task_names = ("mnli", "mnli-mm") if args.task_name == "mnli" else (args.task_name,)
eval_outputs_dirs = (args.output_dir, args.output_dir + '-MM') if args.task_name == "mnli" else (args.output_dir,)
results = {}
for eval_task, eval_output_dir in zip(eval_task_names, eval_outputs_dirs):
eval_dataset = load_and_cache_examples(args, eval_task, tokenizer, evaluate=True)
if not os.path.exists(eval_output_dir) and args.local_rank in [-1, 0]:
os.makedirs(eval_output_dir)
args.eval_batch_size = args.per_gpu_eval_batch_size * max(1, args.n_gpu)
# Note that DistributedSampler samples randomly
eval_sampler = SequentialSampler(eval_dataset) if args.local_rank == -1 else DistributedSampler(eval_dataset)
eval_dataloader = DataLoader(eval_dataset, sampler=eval_sampler, batch_size=args.eval_batch_size)
# multi-gpu eval
if args.n_gpu > 1:
model = torch.nn.DataParallel(model)
# Eval!
logger.info("***** Running evaluation {} *****".format(prefix))
logger.info(" Num examples = %d", len(eval_dataset))
logger.info(" Batch size = %d", args.eval_batch_size)
eval_loss = 0.0
nb_eval_steps = 0
preds = None
out_label_ids = None
for batch in tqdm(eval_dataloader, desc="Evaluating"):
model.eval()
batch = tuple(t.to(args.device) for t in batch)
with torch.no_grad():
inputs = {'input_ids': batch[0],
'attention_mask': batch[1],
'labels': batch[3]}
if args.model_type != 'distilbert':
inputs['token_type_ids'] = batch[2] if args.model_type in ['bert', 'xlnet'] else None # XLM, DistilBERT and RoBERTa don't use segment_ids
outputs = model(**inputs)
tmp_eval_loss, logits = outputs[:2]
eval_loss += tmp_eval_loss.mean().item()
nb_eval_steps += 1
if preds is None:
preds = logits.detach().cpu().numpy()
out_label_ids = inputs['labels'].detach().cpu().numpy()
else:
preds = np.append(preds, logits.detach().cpu().numpy(), axis=0)
out_label_ids = np.append(out_label_ids, inputs['labels'].detach().cpu().numpy(), axis=0)
eval_loss = eval_loss / nb_eval_steps
if args.output_mode == "classification":
preds = np.argmax(preds, axis=1)
elif args.output_mode == "regression":
preds = np.squeeze(preds)
result = compute_metrics(eval_task, preds, out_label_ids)
results.update(result)
output_eval_file = os.path.join(eval_output_dir, prefix, "eval_results.txt")
with open(output_eval_file, "w") as writer:
logger.info("***** Eval results {} *****".format(prefix))
for key in sorted(result.keys()):
logger.info(" %s = %s", key, str(result[key]))
writer.write("%s = %s\n" % (key, str(result[key])))
return results
def load_and_cache_examples(args, task, tokenizer, evaluate=False):
if args.local_rank not in [-1, 0] and not evaluate:
torch.distributed.barrier() # Make sure only the first process in distributed training process the dataset, and the others will use the cache
processor = processors[task]()
output_mode = output_modes[task]
# Load data features from cache or dataset file
cached_features_file = os.path.join(args.data_dir, 'cached_{}_{}_{}_{}'.format(
'dev' if evaluate else 'train',
list(filter(None, args.model_name_or_path.split('/'))).pop(),
str(args.max_seq_length),
str(task)))
if os.path.exists(cached_features_file) and not args.overwrite_cache:
logger.info("Loading features from cached file %s", cached_features_file)
features = torch.load(cached_features_file)
else:
logger.info("Creating features from dataset file at %s", args.data_dir)
label_list = processor.get_labels()
if task in ['mnli', 'mnli-mm'] and args.model_type in ['roberta']:
# HACK(label indices are swapped in RoBERTa pretrained model)
label_list[1], label_list[2] = label_list[2], label_list[1]
examples = processor.get_dev_examples(args.data_dir) if evaluate else processor.get_train_examples(args.data_dir)
features = convert_examples_to_features(examples,
tokenizer,
label_list=label_list,
max_length=args.max_seq_length,
output_mode=output_mode,
pad_on_left=bool(args.model_type in ['xlnet']), # pad on the left for xlnet
pad_token=tokenizer.convert_tokens_to_ids([tokenizer.pad_token])[0],
pad_token_segment_id=4 if args.model_type in ['xlnet'] else 0,
)
if args.local_rank in [-1, 0]:
logger.info("Saving features into cached file %s", cached_features_file)
torch.save(features, cached_features_file)
if args.local_rank == 0 and not evaluate:
torch.distributed.barrier() # Make sure only the first process in distributed training process the dataset, and the others will use the cache
# Convert to Tensors and build dataset
all_input_ids = torch.tensor([f.input_ids for f in features], dtype=torch.long)
all_attention_mask = torch.tensor([f.attention_mask for f in features], dtype=torch.long)
all_token_type_ids = torch.tensor([f.token_type_ids for f in features], dtype=torch.long)
if output_mode == "classification":
all_labels = torch.tensor([f.label for f in features], dtype=torch.long)
elif output_mode == "regression":
all_labels = torch.tensor([f.label for f in features], dtype=torch.float)
dataset = TensorDataset(all_input_ids, all_attention_mask, all_token_type_ids, all_labels)
return dataset
3. Apply the dynamic quantization¶
We call torch.quantization.quantize_dynamic
on the model to apply
the dynamic quantization on the HuggingFace BERT model. Specifically,
We specify that we want the torch.nn.Linear modules in our model to be quantized;
We specify that we want weights to be converted to quantized int8 values.
quantized_model = torch.quantization.quantize_dynamic(
model, {torch.nn.Linear}, dtype=torch.qint8
)
print(quantized_model)
3.1 Check the model size¶
Let’s first check the model size. We can observe a significant reduction in model size (FP32 total size: 438 MB; INT8 total size: 181 MB):
def print_size_of_model(model):
torch.save(model.state_dict(), "temp.p")
print('Size (MB):', os.path.getsize("temp.p")/1e6)
os.remove('temp.p')
print_size_of_model(model)
print_size_of_model(quantized_model)
The BERT model used in this tutorial (bert-base-uncased
) has a
vocabulary size V of 30522. With the embedding size of 768, the total
size of the word embedding table is ~ 4 (Bytes/FP32) * 30522 * 768 =
90 MB. So with the help of quantization, the model size of the
non-embedding table part is reduced from 350 MB (FP32 model) to 90 MB
(INT8 model).
3.2 Evaluate the inference accuracy and time¶
Next, let’s compare the inference time as well as the evaluation accuracy between the original FP32 model and the INT8 model after the dynamic quantization.
def time_model_evaluation(model, configs, tokenizer):
eval_start_time = time.time()
result = evaluate(configs, model, tokenizer, prefix="")
eval_end_time = time.time()
eval_duration_time = eval_end_time - eval_start_time
print(result)
print("Evaluate total time (seconds): {0:.1f}".format(eval_duration_time))
# Evaluate the original FP32 BERT model
time_model_evaluation(model, configs, tokenizer)
# Evaluate the INT8 BERT model after the dynamic quantization
time_model_evaluation(quantized_model, configs, tokenizer)
Running this locally on a MacBook Pro, without quantization, inference (for all 408 examples in MRPC dataset) takes about 160 seconds, and with quantization it takes just about 90 seconds. We summarize the results for running the quantized BERT model inference on a Macbook Pro as the follows:
| Prec | F1 score | Model Size | 1 thread | 4 threads |
| FP32 | 0.9019 | 438 MB | 160 sec | 85 sec |
| INT8 | 0.8953 | 181 MB | 90 sec | 46 sec |
We have 0.6% F1 score accuracy after applying the post-training dynamic quantization on the fine-tuned BERT model on the MRPC task. As a comparison, in a recent paper (Table 1), it achieved 0.8788 by applying the post-training dynamic quantization and 0.8956 by applying the quantization-aware training. The main difference is that we support the asymmetric quantization in PyTorch while that paper supports the symmetric quantization only.
Note that we set the number of threads to 1 for the single-thread
comparison in this tutorial. We also support the intra-op
parallelization for these quantized INT8 operators. The users can now
set multi-thread by torch.set_num_threads(N)
(N
is the number of
intra-op parallelization threads). One preliminary requirement to enable
the intra-op parallelization support is to build PyTorch with the right
backend
such as OpenMP, Native or TBB.
You can use torch.__config__.parallel_info()
to check the
parallelization settings. On the same MacBook Pro using PyTorch with
Native backend for parallelization, we can get about 46 seconds for
processing the evaluation of MRPC dataset.
3.3 Serialize the quantized model¶
We can serialize and save the quantized model for the future use.
quantized_output_dir = configs.output_dir + "quantized/"
if not os.path.exists(quantized_output_dir):
os.makedirs(quantized_output_dir)
quantized_model.save_pretrained(quantized_output_dir)
Conclusion¶
In this tutorial, we demonstrated how to demonstrate how to convert a well-known state-of-the-art NLP model like BERT into dynamic quantized model. Dynamic quantization can reduce the size of the model while only having a limited implication on accuracy.
Thanks for reading! As always, we welcome any feedback, so please create an issue here if you have any.
References¶
[1] J.Devlin, M. Chang, K. Lee and K. Toutanova, BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding (2018).
[3] O. Zafrir, G. Boudoukh, P. Izsak, and M. Wasserblat (2019). Q8BERT: Quantized 8bit BERT.


Can you join us in this campaign to protect young people in North Carolina from the dangerous and debunked practice of "conversion therapy"? Take the pledge here to stand with us. This campaign is backed by a growing statewide coalition of clergy, LGBTQ and civil rights groups, mental health advocates, and youth advocates – and we want you to join the coalition too!
One of the most important things we can do right now to support LGBTQ young people is to urge our representatives in the North Carolina General Assembly to support this legislation protecting young people from "conversion therapy."
Take action now and urge your representatives and Senators in North Carolina to support and prioritize the Mental Health Protection Act.
Since the introduction of the Mental Health Protection Act, we’ve garnered unprecedented support from North Carolina legislators, with dozens co-sponsoring the legislation. This is exactly the kind of support we need to help protect the LGBTQ youth of North Carolina from the dangers of “conversion therapy.”
Will you help us thank these legislators for their support of the Mental Health Protection Act? Take action now and urge your representatives and Senators in North Carolina to support and prioritize the Mental Health Protection Act.
Share your story with Protect Our Youth NC!


@* * Copyright 2019 HM Revenue & Customs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *@ @import config.FrontendAppConfig @import uk.gov.hmrc.play.views.html._ @import models.{Mode, CheckMode} @import controllers.register.company.routes._ @(appConfig: FrontendAppConfig, companyName: String, directors: Seq[String])(implicit request: Request[_], messages: Messages) @main_template( title = messages("companyReview.title"), appConfig = appConfig, bodyClasses = None) { @components.heading(messages("companyReview.heading")) @components.review_section( heading = companyName, linkMessage = "companyReview.editLink", linkId = "edit-company-details", link = CheckYourAnswersController.onPageLoad ) @components.review_section( heading = messages("companyReview.directors.heading"), linkMessage = if(directors.lengthCompare(10)<0){ "companyReview.directors.editLink" } else { "companyReview.directors.changeLink" }, linkId = "edit-director-details", link = AddCompanyDirectorsController.onPageLoad(NormalMode), list = Some(directors) ) @helpers.form(action = CompanyReviewController.onSubmit, 'autoComplete -> "off") {


---
layout: post
title: links for 2007-01-08
date: 2007-01-08 00:00:00
---
-
Very brave to post this sort of stuff :)
-
Heh. In the spirit of doing incremental improvements not just to our software, but to the whole way we work at FP, we're working hard on time-keeping and meeting discipline at the start of the year. Just getting to work on time, starting meetings when you
-
-
-
-
-


Server side data binding allow users to bind large data sets that are not directly accessible as a full collection in client side due to various reasons. Server side data binding can improve performance drastically for large data sets but integration is fairly complex compared to Client Side Basic Data Binding and Client Side Stream Data Binding techniques.
Unlike in Client Side Basic Data Binding, server side rendering will request for data on dropdown initialization and whenever user performs Server Side Filtering operation. Ornamentum has provided an optional opinionated service to integrate external data sources. Also, you can build a custom data provider depending on your requirement.
Server side data binding is handled via onDataBind callback function. Use this callback reference to hook into data bind workflow and provide custom data source. This callback function will get triggered on dropdown initialization and on dynamic dropdown operations. It receives DropdownRequestParams argument and expect to return RxJS Observable query result DropdownQueryResult<T> object stream. Data returned from this callback function will be directly bound to dropdown assuming that it matches the on demand request context.
For use of Server side basic data binding operations it is mandatory to import DropdownResourceModule to your application module.
Following code snippet represent an example implementation of onDataBind callback.