The Importance of Terminology and sRGB Uncertainty
We were meant to write that entry since a while, and a great post by Tom Forsyth from Oculus VR triggered us in doing so.
As I was quickly reading his article, I tweeted back about the missing description of sRGB as being an RGB colourspace: a set of primaries, whitepoint and transfer functions components.
The article first description of sRGB is as follows:
sRGB is a slight tweaking of the simple gamma 2.2 curve.
While this depiction of sRGB colourspace Electro-Optical Transfer Function (EOTF) is exact, it may be confusing for non experts by omitting an explicit emphasis of the components of an RGB colourspace.
For people experienced with colour theory and science, the post title and the mention of Gamma indicates that the article will likely only involves the sRGB colourspace EOTF and its inverse.
Tom confirms that intuition a few paragraph later:
(the broader sRGB standard also has a bunch of gamut and colour-transform specifications, but we’ll ignore those and just focus on the gamma-curve part for now, since that is what concerns us for graphics rendering)
What is sRGB?
Terminology in a given scientific domain is key to its understanding, and this is especially true in colour science. Everybody knows what colour is but yet only a few can define it correctly, in this regard, we often cite Mark D. Fairchild:
Why should it be particularly difficult to agree upon consistent terminology in the field of color appearance? Perhaps the answer lies in the very nature of the subject. Almost everyone knows what color is. After all, they have had firsthand experience of it since shortly after birth. However, very few can precisely describe their color experiences or even precisely define color. [1]
sRGB is not a bunch of transfer functions, it is an actual RGB colourspace, specified by the IEC 61966-2-1:1999 Standard. As per ISO 22028-1 Standard, an RGB colourspace is defined by those mandatory 3 components:
The ISO 22028-1 Standard definition of an additive RGB colourspace is quoted in its entirety for reference:
3.3
additive RGB colour space
colorimetric colour space having three colour primaries (generally red, green and blue) such that CIE XYZ tristimulus values can be determined from the RGB colour space values by forming a weighted combination of the CIE XYZ tristimulus values for the individual colour primaries, where the weights are proportional to the radio-metrically linear colour space values for the corresponding colour primaries
Note 1 to entry: A simple linear 3 × 3 matrix transformation can be used to transform between CIE XYZ tristimulus values and the radio-metrically linear colour space values for an additive RGB colour space.
Note 2 to entry: Additive RGB colour spaces are defined by specifying the CIE chromaticity values for a set of additive RGB primaries and a colour space white point, together with a colour component transfer function.
Primaries
The primaries chromaticity coordinates define the gamut (the triangle of colours) that can be encoded by a given RGB colourspace.
It is important to understand that while commonly represented as triangles on a Chromaticity Diagram (such as the CIE 1931 Chromaticity Diagram), RGB colourspace gamuts define the boundaries of an actual 3D volume within the CIE xyY colourspace: The Chromaticity Diagram is a 2D projection of the CIE xyY colourspace volume along its Y Luminance axis.
Whitepoint
The whitepoint is defined by the CIE as:
Achromatic reference stimulus in a chromaticity diagram that corresponds to the stimulus that produces an image area that has the perception of white.
Any set of colours lying on the neutral axis passing through the whitepoint, no matter their Luminance, will be neutral to that RGB colourspace.
An RGB colourspace can have different whitepoints depending its context usage, sRGB colourspace IEC 61966-2-1:1999 Standard adopts CIE Standard Illuminant D65 as whitepoint but an ICC sRGB colourspace profile would likely have been chromatically adapted to CIE Standard Illuminant D50.
Transfer Functions
The transfer functions perform the mapping between the linear light components (tristimulus values) and a non-linear R'G'B' video signal (most of the time for coding optimisation and bandwidth performance). [2]
The two common types and their inverses are defined as follows:
-
The Opto-Electronic Transfer Function (OETF) maps estimated tristimulus values in a scene to a non-linear R'G'B' video component signal value. Typical OETFs are expressed by a power function with an exponent between 0.4 and 0.5. They can also be defined as piece-wise functions, SMPTE 240M or BT.709 OETFs are such examples.
-
The Electro-Optical Transfer Function (EOTF) maps a non-linear R'G'B' video component signal to a tristimulus value at the display. Typical EOTFs are expressed by a power function with an exponent between 2.2 and 2.6 or a piece-wise function.
The Importance of Terminology
With the RGB colourspace specification components outlined, it should now make more sense why not being specific and using a clear terminology can lead to confusion and uncertainty: colour science vocabulary is complex.
I often encounter people that don’t have a clear understanding on what composes an RGB colourspace, as a result they don't properly differentiate gamut and transfer functions. The cursory terminology recurrently used online is probably the root cause for that.
When one talks about sRGB, is he describing the colourspace primaries or its transfer functions? Discussing about sRGB to linear transformation without emphasis on the EOTF component is unsettling: a rendering engine using linear sRGB colourspace input colours and textures, renders with the sRGB colourspace primaries and whitepoint (assuming no colour transformations are occurring internally), thus its output is within sRGB colourspace.
When rendering using BT.709 colourspace for HDTV, one is actually adopting sRGB colourspace primaries and whitepoint with different specific transfer functions.
Movie cameras such as those from Canon (Canon EOS 1DC, Canon CX00) use BT.709 primaries and whitepoint but encode their scene linear values with a custom log curve designated C-Log.
Likewise, it is perfectly valid to use the sRGB colourspace transfer functions with another set of primaries and whitepoint. When working within Adobe Photoshop or The Foundry Mari, some VFX studios use a proprietary colourspace specification along sRGB colourspace transfer functions: those transfer functions being commonly implemented in various DCC packages, the various colour transformation operations between those packages are simplified.
Conclusion
When one talks about sRGB alone, it should be safe to assume that he is referring to the sRGB colourspace as per IEC 61966-2-1:1999 Standard, not just cherry picked components. Unfortunately it is not the case thus in order to lessen the uncertainty and improve the terminology used, we suggest that:
-
One remembers that a given RGB colourspace is defined by the following essential three components:
When writing on the RGB colourspace topic, one should ideally mention the previous point, it will help people getting the grasp on the theory.
-
When discussing about a given RGB colourspace component, one should make a point of describing which specification's component he is referring to:
sRGB is a slight tweaking of the simple gamma 2.2 curve.
would be better written as follows:
The sRGB transfer function is a slight tweaking of the simple gamma 2.2 curve.
or for completeness:
The sRGB Electro-Optical Transfer Function (EOTF) is a slight tweaking of the simple Gamma 2.2 function.
-
When describing an RGB colourspace not supported by an official specification or standard, one should probably use a name that explicitly defines the complete specification:
sRGB-D60-Linear: an RGB colourspace using sRGB primaries chromatically adapted to CIE Standard Illuminant D60 whitepoint and linear transfer functions.
Adobe 1998 RGB-D65-Gamma1.8: an RGB colourspace using Adobe 1998 RGB primaries, CIE Standard Illuminant D65 whitepoint and Gamma 1.8 transfer functions.
In the near future it will likely become even more critical and relevant as new RGB colourspaces such as BT.2020 or the ACES encodings become mainstream.
Comments
Comments powered by Disqus


State and City. Oh and a little Seoul too. | Learn a bit more |
Location is not overly important in search at the moment. Eventually with personalization programs, we can begin doing a better job targeting.
We are consistent in our top 10 states and cities.
What is interesting is that seasonally our top 10 states do not vary much. Even rather southern states such as Florida and Texas do not show much change in traffic due to seasons.
Again the top 10 cities are rather consistent and map to the states. The one huge outlier is Seoul South Korea which pops up in our city top 10. Given that these values are based on traffic and not revenue, it is pretty impressive that we get this much attention from a SE Asian country.
Visitor location
Not overly important to search, but interesting non the less.


Summer In The Library
26 Aug 2014 tagged in archives life, charles w morgan, library, ma history, me at the archives, museum life, nbwm, new bedford, new bedford whaling musum, summer 2014Here’s what I love about historians: they are storytellers. Whether we know it consciously or simply find our way there, we search the past for a semblance of something relatable or funny or interesting. We further our interests (or those of others) in efforts to remember something worth remembering.
On the other hand, archivists and librarians collect stories. They house materials in order to keep them in context, providing the information to the world, only if you know where to look.
There could not be a better match.
I was extremely excited to join the New Bedford Whaling Museum as an intern this summer, I’ve grown especially fond of its history and legacy over the past year. I applied to the Archives & Library position as I figured in my goal of becoming a professor, I’ll have to do a lot of work with archival research. I wanted a behind-the-scenes look at things – being able to see researchers in their element while discovering just what it is they look at.
The bulk was devoted to Mss (Manuscript) collections, which featured a little bit of everything in Old Dartmouth local history.Though many of these collections had been accessioned by the museum, they hadn’t been processed or given a proper finding aid so that researchers could make use of the materials. So, I took inventories, processed and organized the contents of various folders, created finding aids, and then coded the information for the Museum website.
These tasks, though long and sometimes difficult, it was my favorite job. It was reading moments in time, getting some pieces of evidence and having to form a coherent storyline through folders and boxes And the stories were endless. I looked at documents from the very beginnings of the Dartmouth/New Bedford area (late 17th century) to letters from the early 1990s.
In regards to whaling, I learned an enormous amount. With the 38th voyage of the Charles W. Morgan, this was a perfect summer to fully immerse myself in the city’s whaling history. I was able to see multiple sides of the story – whalers writing home to their wives and children explaining day-to-day activities on board; businessmen managing their vessels and crew from home; wives and children describing life in bustling communities thriving on the maritime economy. I saw its rise as an American industry, the city’s prominence as the whaling capital, and its decline (especially with the Arctic disasters of the 1870s.) Encompassing myself in this time was fascinating because there was always a new angle from which to view the industry. And just being in the research library, I was surrounded by an overwhelming amount of information that I began to understand how influential whaling truly was to the Old Dartmouth area.
But it wasn’t all about whaling – I explored topics like Joshua Slocum’s solo circumnavigation of the globe (Teller Collection), the Gold Rush (Rounsevell Family Papers), life in Martha’s Vineyard (Eliza Russell Papers), beginnings of mill construction (Howland Family Papers), and antique dealers (Winfred W. Bennett Papers), just to name a few. The pacing of the job was probably my favorite aspect – I was able to study a wide range of subjects in a short period of time, without an overwhelming feeling.
I also got to spend some time on the digital side of things – learning to code was surprisingly easy once I got the hang of it. (I still keep the template out just in case, though.) The most helpful tip when it comes to digital collections is management is this: LOCKSS (Lots Of Copies Keeps Stuff Safe.) While downloading logbook files, converting file formats, and uncovering bugs in a code weren’t the most glamorous of tasks, their importance was undoubtedly valuable. I started to investigate the pressing issues of archives and libraries entering the digital world. Do GLAMs (Galleries, Libraries, Archives, Museums) have the time and capabilities to digitize collections? How should these materials be uploaded? What will happen when servers are filled to capacity?
Although the research library is primarily for the Whaling Museum, it is also home to the collections of the Old Dartmouth Historical Society and the Melville Society. This meant people were coming to the library for tons of different reasons. While a library is not the greatest forum for interaction (my mother was shocked I could spend six hours sitting without talking to anyone), I found that everyone in the library – employees and visitors alike – was friendly and enthusiastic. (My favorite visitors, by far, were the kids from Ocean Explorium. Their confusion over the card catalog and obsession with the possible hidden money in the old bankers’ desk was very adorable.)
My work in the Library focused on two goals: to ease access to research and to preserve the materials. And ultimately, I found that archives intend to do just that. But more so, I learned what librarians and archivists require: a passion for information – for organizing and formatting the mess of materials that arrive, for sharing these materials with others, You are the first one to view these accessions as stories or vignettes of someone’s life, and do so without any background information at all. It’s an amazing job – one I’d love to try my hand at again someday.


{% extends 'base.html' %} {% load staticfiles %} {% block stylesheet %} {% endblock %} {% block content %}
Confirmation Email was success
You can login now
Regards
GoFindMe Team


and the with The for COVID- al. from pandemic {background are that has margin flu have {border-style India May health px;} #ffffff;} will WHO lessons Accessed influenza spread care Health disease learned virus cases public social â€" World first pandemics past March Med coronavirus countries during million precautions through June Spanish against global number other personal treatment Infect all diseases its patients pregnant px; respiratory review was {font-family (â€"), COVID-. Europe, Ministry Report Table also clinical font-size infection infectious medical new not reported their who (); ./s--- Avoid COVID Dis India, India. accessed avoiding been deaths developing double; general given including most novel people severe study support this viral water women :â€". Africa Africa, Coronavirus HIV/AIDS Indian January North Public Social acute after along border-color border-width challenge cholera days distancing due economic economy effects elderly great history lockdown now outbreak outbreaks recent solid; such syndrome taken these they vaccines viruses which {font-style {font-weight (COVID-): (HN) Antonine Asia, Available COVID-, China, DCH Family Res Source: These Welfare Wuhan, any at: available awareness based bold causing centre common continuous control country courier; deadly distancing, distancing; doctors, effective efforts em; emerging facilities gatherings guidelines hands hospital human include live masks, must oxygen pandemic, pandemic. plasma present presented preventive pt;} regarding research second separate should symptoms third throughout time vaccine virology wearing were workers,


Click here to place a new order
This is an order for the following tier(s):
No Tier -
$0
The following rings have been removed: (already subtracted from the tier cost above)
The following rings have been added:
CC6FGEW2UMIL13C/14KY
SATIN/POLISH
299
CC8D12/LAPIS
SANDBLAST
199
D8F11ANGLED/SS
ACID/POLISH
239
6REF11/14KR2UMIL
SATIN/POLISH
149
Z8D/CYCLE2
BEAD
149
CC8D/LCVESCHER1
BEAD
149
CC8HRM/MJBA
BEAD/POLISH
149
8F2S
SATIN/POLISH
35
8D
POLISH
35
ZPF8D14/DAMASCUS
ACID/POLISH
229
FABLE8HR(1)4G-RT-APSNOW
polish
125
FABLE8B(1)4G-RT-APRED
polish
125
7HR(1)4G-RT/APPURPLE
polish
125
10F(1)6G-RT/MAX4
polish
125
Z6D/WLCVSOUNDWAVE
POLISH
199
Z11F17_KINGSWOODLAND
hammer/polish
184
C10F19/CF
polish
129
CC7F
treebark 2
114
CC8DCYCLE3
sand/polish
149
CC6D21W/14KYMIL
satin/polish
0
CC9D21W/14KYMIL
satin/polish
0
14KR9F2S14.5SEG/METDIAPRN.10B
polish
908
SFGE
cross satin/polish
35
Z8B/WLCVSERPENTS
polish
0
CB-8F1GOCHR
HAMMER SATIN/POLISH
114
ZHW9.5FSQ14.5OC/COCOETERNDIA.03
POLISH
1549
8DSTAGGERANODIA3X.03F
BLUE SATIN
199
6D12/MALA
POLISH
129
CC8B/LCVESCHER1
BLUE E COAT/POLISH
164
CC8FGESQETERNITYSAPPHIRE
CROSS SATIN/POLISH
1199
The following other items have been added:
DISPLAY CASE BG
BLACK/GRAY
0
The following custom items have been added:
Your sub-total is:
$7204
Existing Partner
Date: 2015-03-26
Store Name: katys
Last Name: froyd
First Name: katy
Address:
Phone:
e-mail:
City/State: provo
Terms: 60=90
Notes:
Sales Rep: Charles Nielson
Sales Rep e-mail<EMAIL_ADDRESS>Your shipping costs are $50
Order Total: $7254


from .strategy import Strategy
import numpy as np
from torch.utils.data import DataLoader
import pickle
from scipy.spatial.distance import cosine
import sys
import gc
from scipy.linalg import det
from scipy.linalg import pinv as inv
from copy import copy as copy
from copy import deepcopy as deepcopy
import torch
from torch import nn
import random
import math
from torch.nn import functional as F
import argparse
import torch.nn as nn
from collections import OrderedDict
from scipy import stats
import time
import numpy as np
import scipy.sparse as sp
from itertools import product
from sklearn.base import BaseEstimator, ClusterMixin, TransformerMixin
from sklearn.metrics.pairwise import euclidean_distances
from sklearn.metrics.pairwise import pairwise_distances_argmin_min
from sklearn.utils.extmath import row_norms, squared_norm, stable_cumsum
from sklearn.utils.sparsefuncs_fast import assign_rows_csr
from sklearn.utils.sparsefuncs import mean_variance_axis
from sklearn.utils.validation import _num_samples
from sklearn.utils import check_array
from sklearn.utils import gen_batches
from sklearn.utils import check_random_state
from sklearn.utils.validation import check_is_fitted
from sklearn.utils.validation import FLOAT_DTYPES
from sklearn.metrics.pairwise import rbf_kernel as rbf
#from sklearn.externals.six import string_types
from sklearn.exceptions import ConvergenceWarning
from sklearn.metrics import pairwise_distances
def init_centers(X, K):
device = "cuda" if torch.cuda.is_available() else "cpu"
pdist = nn.PairwiseDistance(p=2)
ind = np.argmax([np.linalg.norm(s, 2) for s in X])
mu = [X[ind]]
indsAll = [ind]
centInds = [0.] * len(X)
cent = 0
#print('#Samps\tTotal Distance')
while len(mu) < K:
if len(mu) == 1:
t0 = time.time()
D2 = pdist(torch.from_numpy(X).to(device), torch.from_numpy(mu[-1]).to(device))
D2 = torch.flatten(D2)
D2 = D2.cpu().numpy().astype(float)
else:
newD = pdist(torch.from_numpy(X).to(device), torch.from_numpy(mu[-1]).to(device))
newD = torch.flatten(newD)
newD = newD.cpu().numpy().astype(float)
for i in range(len(X)):
if D2[i] > newD[i]:
centInds[i] = cent
D2[i] = newD[i]
if sum(D2) == 0.0: pdb.set_trace()
D2 = D2.ravel().astype(float)
Ddist = (D2 ** 2)/ sum(D2 ** 2)
customDist = stats.rv_discrete(name='custm', values=(np.arange(len(D2)), Ddist))
ind = customDist.rvs(size=1)[0]
mu.append(X[ind])
indsAll.append(ind)
cent += 1
#gram = np.matmul(X[indsAll], X[indsAll].T)
#val, _ = np.linalg.eig(gram)
#val = np.abs(val)
#vgt = val[val > 1e-2]
return indsAll
[docs]class BADGE(Strategy):
"""
Implementation of Deep Batch Active Learning by Diverse, Uncertain Gradient Lower Bounds (BADGE)
:footcite:`DBLP:journals/corr/abs-1906-03671` Strategy. This class extends :
class:`active_learning_strategies.strategy.Strategy`.
This method is based on the paper `Deep Batch Active Learning by Diverse, Uncertain Gradient Lower Bounds <https://arxiv.org/abs/1906.03671>`_
According to the paper, Batch Active learning by Diverse Gradient Embeddings (BADGE), samples groups of points that are disparate and high magnitude when represented in a hallucinated gradient space, a strategy designed to incorporate both predictive uncertainty and sample diversity into every selected batch.
Crucially, BADGE trades off between uncertainty and diversity without requiring any hand-tuned hyperparameters.
Here at each round of selection, loss gradients are computed using the hypothesised labels. Then to select the points to be labeled are selected by applying k-means++ on these loss gradients.
Parameters
----------
X: Numpy array
Features of the labled set of points
Y: Numpy array
Lables of the labled set of points
unlabeled_x: Numpy array
Features of the unlabled set of points
net: class object
Model architecture used for training. Could be instance of models defined in `distil.utils.models` or something similar.
handler: class object
It should be a subclasses of torch.utils.data.Dataset i.e, have __getitem__ and __len__ methods implemented, so that is could be passed to pytorch DataLoader.Could be instance of handlers defined in `distil.utils.DataHandler` or something similar.
nclasses: int
No. of classes in tha dataset
args: dictionary
This dictionary should have 'batch_size' as a key.
"""
def __init__(self, X, Y, unlabeled_x, net, handler,nclasses, args):
super(BADGE, self).__init__(X, Y, unlabeled_x, net, handler,nclasses, args)
[docs] def select_per_batch(self, budget, batch_size):
"""
Select points to label by using per-batch BADGE strategy
Parameters
----------
budget : int
Number of indices to be selected from unlabeled set
batch_size : TYPE
Size of batches to form
Returns
-------
chosen: list
List of selected data point indices with respect to unlabeled_x
"""
if torch.cuda.is_available():
device = "cuda"
else:
device = "cpu"
# Compute gradient embeddings of each unlabeled point
grad_embedding = self.get_grad_embedding(self.unlabeled_x,bias_grad=False)
# Calculate number of batches to choose from, embedding dimension, and adjusted budget
num_batches = math.ceil(grad_embedding.shape[0] / batch_size)
embed_dim = grad_embedding.shape[1]
batch_budget = math.ceil(budget / batch_size)
# Instantiate list of lists of indices drawn from the possible range of the gradient embedding
batch_indices_list = []
draw_without_replacement = list(range(grad_embedding.shape[0]))
while len(draw_without_replacement) > 0:
if len(draw_without_replacement) < batch_size:
batch_random_sample = draw_without_replacement
else:
batch_random_sample = random.sample(draw_without_replacement, batch_size)
batch_indices_list.append(batch_random_sample)
for index in batch_random_sample:
draw_without_replacement.remove(index)
# Instantiate batch average tensor
gradBatchEmbedding = torch.zeros([num_batches, embed_dim]).to(device)
# Calculate the average vector embedding of each batch
for i in range(num_batches):
indices = batch_indices_list[i]
vec_avg = torch.zeros(embed_dim).to(device)
for index in indices:
vec_avg = vec_avg + grad_embedding[index]
vec_avg = vec_avg / len(indices)
gradBatchEmbedding[i] = vec_avg
# Perform initial centers problem using new budget
chosen_batch = init_centers(gradBatchEmbedding.cpu().numpy(), batch_budget)
# For each chosen batch, construct the list of indices to return.
chosen = []
for batch_index in chosen_batch:
indices_to_add = batch_indices_list[batch_index]
chosen.extend(indices_to_add)
return chosen
[docs] def select(self, budget):
"""
Select next set of points
Parameters
----------
budget: int
Number of indexes to be returned for next set
Returns
----------
chosen: list
List of selected data point indexes with respect to unlabeled_x
"""
gradEmbedding = self.get_grad_embedding(self.unlabeled_x,bias_grad=False)
chosen = init_centers(gradEmbedding.cpu().numpy(), budget)
return chosen


Two hurt when pirates attack Italian ship in Gulf of Mexico, officials say
by Louis CasianoTwo crew members on an Italian-flagged ship were injured when the vessel was attacked by pirates in the Gulf of Mexico, the Mexican navy said Tuesday.
One crew member aboard the "Remas" had a bullet wound and the other suffered a concussion, officials told Reuters. Both men were taken to a hospital. Their conditions were not immediately available.
The "Remas" is a supply vessel for Mexico's oil industry and is owned by Micoperi, an Italian contractor.
MEXICAN PIRATES POSING GREATER RISK IN GULF OF MEXICO TO OIL WORKERS, TOURISTS
The attack was carried out by around eight armed men who boarded the ship from two fishing boats off the coast of Ciudad del Carmen in the southeastern Mexican state of Campeche.
CLICK HERE TO GET THE FOX NEWS APP
The "Remas" had a crew of about 35 when the attack occurred.
The southern Gulf of Mexico has seen an increase in pirate attacks on boats and oil platforms in recent years.


Package com.jme.material
-
Class Summary Class Description Material Material
describes the rendering style for a givenGeometry
.MaterialDef Describes a J3MD (Material definition).MaterialList A map from material name to a material.MaterialProcessor Materials This class is to provide some constants materials.MatParam Describes a material parameter.MatParamOverride MatParamOverride
is a mechanism by whichmaterial parameters
can be overridden on the scene graph.MatParamTexture RenderState RenderState
specifies material rendering properties that cannot be controlled by a shader on aMaterial
.ShaderGenerationInfo this class is basically a struct that contains the ShaderNodes informations in an appropriate way to ease the shader generation process and make it faster.Technique Represents a technique instance.TechniqueDef Describes a technique definition. -
Enum Summary Enum Description RenderState.BlendEquation BlendEquation
specifies the blending equation to combine pixels.RenderState.BlendEquationAlpha BlendEquationAlpha
specifies the blending equation to combine pixels for the alpha component.RenderState.BlendFunc BlendFunc
defines the blending functions for use withBlendMode.Custom
.RenderState.BlendMode BlendMode
specifies the blending operation to use.RenderState.FaceCullMode FaceCullMode
specifies the criteria for faces to be culled.RenderState.StencilOperation StencilOperation
specifies the stencil operation to use in a certain scenario as specified inRenderState.setStencil(boolean, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.StencilOperation, com.jme.material.RenderState.TestFunction, com.jme.material.RenderState.TestFunction)
RenderState.TestFunction TestFunction
specifies the testing function for stencil test function.TechniqueDef.LightMode Describes light rendering mode.TechniqueDef.LightSpace Define in what space the light data should be sent to the shader.TechniqueDef.ShadowMode


Source code for torch.autograd.profiler
from typing import Any, Dict, List, Optional
from collections import defaultdict
from warnings import warn
import torch
import torch.cuda
from torch._C._profiler import _ExperimentalConfig
from torch.autograd import (
_disable_profiler,
_enable_profiler,
_kineto_step,
_prepare_profiler,
_ProfilerResult,
_supported_activities,
DeviceType,
kineto_available,
ProfilerActivity,
ProfilerConfig,
ProfilerState,
)
from torch.autograd.profiler_util import (
_filter_name,
_filter_stack_entry,
_rewrite_name,
EventList,
FunctionEvent,
MEMORY_EVENT_NAME,
MemRecordsAcc,
OUT_OF_MEMORY_EVENT_NAME,
)
from torch.futures import Future
__all__ = ["profile", "record_function", "emit_itt", "emit_nvtx", "load_nvprof", "EnforceUnique",
"parse_nvprof_trace", "KinetoStepTracker", "EventList", "FunctionEvent", "MemRecordsAcc"]
try:
# Available in Python >= 3.2
from contextlib import ContextDecorator as _ContextDecorator
except ImportError:
import functools
class _ContextDecorator: # type: ignore[no-redef]
def __enter__(self):
raise NotImplementedError
def __exit__(self, exc_type, exc_val, exc_tb):
raise NotImplementedError
def __call__(self, func):
@functools.wraps(func)
def wrapped(*args, **kwargs):
with self:
return func(*args, **kwargs)
return wrapped
def _enable_dynamo_cache_lookup_profiler(enable: bool):
from torch._dynamo.eval_frame import ( # type: ignore[attr-defined]
clear_profiler_hooks,
set_profiler_hooks,
)
"""
Registers a hook within dynamo eval_frame.c called before and after
the lookup process, which runs guards associated with each cached frame.
Clear deregisters the hooks, saving overhead.
"""
if enable:
def _profiler_start(name):
return torch.ops.profiler._record_function_enter_new(name, None)
def _profiler_end(record):
torch.ops.profiler._record_function_exit._RecordFunction(record)
set_profiler_hooks(_profiler_start, _profiler_end)
else:
clear_profiler_hooks()
[docs]class profile:
"""Context manager that manages autograd profiler state and holds a summary of results.
Under the hood it just records events of functions being executed in C++ and
exposes those events to Python. You can wrap any code into it and it will
only report runtime of PyTorch functions.
Note: profiler is thread local and is automatically propagated into the async tasks
Args:
enabled (bool, optional): Setting this to False makes this context manager a no-op.
use_cuda (bool, optional): Enables timing of CUDA events as well using the cudaEvent API.
Adds approximately 4us of overhead to each tensor operation.
record_shapes (bool, optional): If shapes recording is set, information
about input dimensions will be collected. This allows one to see which
dimensions have been used under the hood and further group by them
using prof.key_averages(group_by_input_shape=True). Please note that
shape recording might skew your profiling data. It is recommended to
use separate runs with and without shape recording to validate the timing.
Most likely the skew will be negligible for bottom most events (in a case
of nested function calls). But for higher level functions the total
self cpu time might be artificially increased because of the shape
collection.
with_flops (bool, optional): If with_flops is set, the profiler will estimate
the FLOPs (floating point operations) value using the operator's input shape.
This allows one to estimate the hardware performance. Currently,
this option only works for the matrix multiplication and 2D convolution operators.
profile_memory (bool, optional): track tensor memory allocation/deallocation.
with_stack (bool, optional): record source information (file and line number) for the ops.
with_modules (bool): record module hierarchy (including function names)
corresponding to the callstack of the op. e.g. If module A's forward call's
module B's forward which contains an aten::add op,
then aten::add's module hierarchy is A.B
Note that this support exist, at the moment, only for TorchScript models
and not eager mode models.
use_kineto (bool, optional): experimental, enable profiling with Kineto profiler.
use_cpu (bool, optional): profile CPU events; setting to ``False`` requires
``use_kineto=True`` and can be used to lower the overhead for GPU-only profiling.
experimental_config (_ExperimentalConfig) : A set of experimental options
used by profiler libraries like Kineto. Note, backward compatibility is not guaranteed.
.. warning:
Enabling memory profiling or source attribution incurs additional profiler
overhead
.. warning:
This context managers should not be called recursively, i.e. no nested
instances are allowed
.. warning:
Due to some CUDA multiprocessing limitations (multiprocessing-cuda-note_),
one cannot use the profiler with ``use_cuda = True`` to benchmark
DataLoaders with ``num_workers > 0``. If you wish to benchmark data loading,
please use ``use_cuda = False`` or ``num_workers = 0``.
Example:
>>> # xdoctest: +SKIP
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_AUTOGRAD_PROFILER)
>>> x = torch.randn((1, 1), requires_grad=True)
>>> with torch.autograd.profiler.profile() as prof:
>>> for _ in range(100): # any normal python code, really!
>>> y = x ** 2
>>> y.backward()
>>> # NOTE: some columns were removed for brevity
>>> print(prof.key_averages().table(sort_by="self_cpu_time_total"))
----------------------------------- --------------- --------------- ---------------
Name Self CPU total CPU time avg Number of Calls
----------------------------------- --------------- --------------- ---------------
mul 32.048ms 32.048ms 200
pow 27.041ms 27.041ms 200
PowBackward0 9.727ms 55.483ms 100
torch::autograd::AccumulateGrad 9.148ms 9.148ms 100
torch::autograd::GraphRoot 691.816us 691.816us 100
----------------------------------- --------------- --------------- ---------------
"""
def __init__(
self,
enabled=True,
*,
use_cuda=False,
record_shapes=False,
with_flops=False,
profile_memory=False,
with_stack=False,
with_modules=False,
use_kineto=False,
use_cpu=True,
experimental_config=None):
self.enabled: bool = enabled
if not self.enabled:
return
self.use_cuda = use_cuda
self.function_events: Optional[EventList] = None
self.entered = False
self.record_shapes = record_shapes
self.with_flops = with_flops
self.record_shapes |= self.with_flops
self.profile_memory = profile_memory
self.with_stack = with_stack
self.with_modules = with_modules
self.use_cpu = use_cpu
if experimental_config is None:
experimental_config = _ExperimentalConfig()
self.experimental_config = experimental_config
self.kineto_results: Optional[_ProfilerResult] = None
if not self.use_cpu:
assert use_kineto, \
"Device-only events supported only with Kineto (use_kineto=True)"
if self.use_cuda and not torch.cuda.is_available():
warn("CUDA is not available, disabling CUDA profiling")
self.use_cuda = False
self.kineto_activities = set()
if self.use_cpu:
self.kineto_activities.add(ProfilerActivity.CPU)
self.profiler_kind = ProfilerState.KINETO
if self.use_cuda:
if (not use_kineto or ProfilerActivity.CUDA not in
_supported_activities()):
assert self.use_cpu, "Legacy CUDA profiling requires use_cpu=True"
self.profiler_kind = ProfilerState.KINETO_GPU_FALLBACK
else:
self.kineto_activities.add(ProfilerActivity.CUDA)
assert len(self.kineto_activities) > 0, \
"No activities specified for the profiler"
def config(self):
return ProfilerConfig(
self.profiler_kind,
self.record_shapes,
self.profile_memory,
self.with_stack,
self.with_flops,
self.with_modules,
self.experimental_config)
def __enter__(self):
if not self.enabled:
return
if self.entered:
raise RuntimeError("Profiler context manager is not reentrant")
_enable_dynamo_cache_lookup_profiler(True)
self._prepare_trace()
self._start_trace()
return self
def _prepare_trace(self):
self.entered = True
_prepare_profiler(self.config(), self.kineto_activities)
def _start_trace(self):
self.entered = True
_enable_profiler(self.config(), self.kineto_activities)
def __exit__(self, exc_type, exc_val, exc_tb):
if not self.enabled:
return
_enable_dynamo_cache_lookup_profiler(False)
if self.use_cuda:
torch.cuda.synchronize()
self.kineto_results = _disable_profiler()
parsed_results = self._parse_kineto_results(self.kineto_results)
self.function_events = EventList(
parsed_results,
use_cuda=self.use_cuda,
profile_memory=self.profile_memory,
with_flops=self.with_flops)
self.function_events._build_tree()
return False
def __repr__(self):
if self.function_events is None:
return '<unfinished torch.autograd.profile>'
return repr(self.function_events)
def __str__(self):
if self.function_events is None:
return '<unfinished torch.autograd.profile>'
return str(self.function_events)
def _check_finish(self):
if self.function_events is None:
raise RuntimeError("Profiler didn't finish running")
def table(
self,
sort_by=None,
row_limit=100,
max_src_column_width=75,
max_name_column_width=55,
max_shapes_column_width=80,
header=None,
top_level_events_only=False
):
self._check_finish()
assert self.function_events is not None
return self.function_events.table(
sort_by=sort_by,
row_limit=row_limit,
max_src_column_width=max_src_column_width,
max_name_column_width=max_name_column_width,
max_shapes_column_width=max_shapes_column_width,
header=header,
top_level_events_only=top_level_events_only
)
table.__doc__ = EventList.table.__doc__
[docs] def export_chrome_trace(self, path):
self._check_finish()
if kineto_available():
self.kineto_results.save(path) # type: ignore[union-attr]
else:
return self.function_events.export_chrome_trace(path) # type: ignore[union-attr]
export_chrome_trace.__doc__ = EventList.export_chrome_trace.__doc__
def export_stacks(self, path: str, metric: str = "self_cpu_time_total"):
self._check_finish()
assert self.function_events is not None, "Expected profiling results"
assert self.with_stack, "export_stacks() requires with_stack=True"
return self.function_events.export_stacks(path, metric)
[docs] def key_averages(self, group_by_input_shape=False, group_by_stack_n=0):
self._check_finish()
assert self.function_events is not None, "Expected profiling results"
return self.function_events.key_averages(group_by_input_shape, group_by_stack_n)
key_averages.__doc__ = EventList.key_averages.__doc__
[docs] def total_average(self):
self._check_finish()
assert self.function_events is not None, "Expected profiling results"
return self.function_events.total_average()
total_average.__doc__ = EventList.total_average.__doc__
@property
def self_cpu_time_total(self):
""" Returns total time spent on CPU obtained as a sum of
all self times across all the events.
"""
self._check_finish()
assert self.function_events is not None
return self.function_events.self_cpu_time_total
def _parse_kineto_results(self, result):
# result.events() has most of the events - PyTorch op-level and device-level events
trace_start_us = result.trace_start_us()
mem_records = [[evt, False] for evt in result.events() if evt.name() == MEMORY_EVENT_NAME]
oom_records = [evt for evt in result.events() if evt.name() == OUT_OF_MEMORY_EVENT_NAME]
mem_records_acc = MemRecordsAcc(mem_records)
def _cpu_memory_usage(mem_record):
return mem_record.nbytes() if \
mem_record.device_type() in [DeviceType.CPU, DeviceType.MKLDNN, DeviceType.IDEEP] \
else 0
def _cuda_memory_usage(mem_record):
return mem_record.nbytes() if \
mem_record.device_type() in [DeviceType.CUDA, DeviceType.HIP] \
else 0
# Create and return FunctionEvent list
function_events = []
cuda_corr_map: Dict[int, List[FunctionEvent]] = {}
max_evt_id = 0
for kineto_event in result.events():
if _filter_name(kineto_event.name()):
continue
rel_start_us = kineto_event.start_us() - trace_start_us
rel_end_us = rel_start_us + kineto_event.duration_us()
abs_end_us = kineto_event.start_us() + kineto_event.duration_us()
cpu_memory_usage = 0
cuda_memory_usage = 0
if kineto_event.device_type() == DeviceType.CPU:
# find the corresponding memory allocation events
for mem_record in mem_records_acc.in_interval(kineto_event.start_us(), abs_end_us):
cpu_memory_usage += _cpu_memory_usage(mem_record[0])
cuda_memory_usage += _cuda_memory_usage(mem_record[0])
mem_record[1] = True
is_async = kineto_event.is_async() or (
kineto_event.start_thread_id() != kineto_event.end_thread_id()
)
fe = FunctionEvent(
id=kineto_event.correlation_id(),
name=_rewrite_name(name=kineto_event.name(), with_wildcard=True),
trace_name=_rewrite_name(name=kineto_event.name(), with_wildcard=False),
thread=kineto_event.start_thread_id(),
start_us=rel_start_us,
end_us=rel_end_us,
fwd_thread=kineto_event.fwd_thread_id(),
input_shapes=kineto_event.shapes(),
stack=[entry for entry in kineto_event.stack() if _filter_stack_entry(entry)],
scope=kineto_event.scope(),
cpu_memory_usage=cpu_memory_usage,
cuda_memory_usage=cuda_memory_usage,
is_async=is_async,
sequence_nr=kineto_event.sequence_nr(),
device_type=kineto_event.device_type(),
device_index=kineto_event.device_index(),
flops=kineto_event.flops(),
)
max_evt_id = fe.id if fe.id > max_evt_id else max_evt_id
if fe.device_type == DeviceType.CPU and not fe.is_async:
# Check if we have CUDA time as a fallback
cuda_time = kineto_event.cuda_elapsed_us()
if cuda_time > 0:
fe.append_kernel(
fe.name,
fe.device_index,
cuda_time)
fe.is_legacy = True
function_events.append(fe)
corr_id = kineto_event.linked_correlation_id()
if corr_id > 0:
if corr_id not in cuda_corr_map:
cuda_corr_map[corr_id] = []
cuda_corr_map[corr_id].append(fe)
# associate CUDA kernels and CUDA runtime (CPU) with CPU events
for fe in function_events:
if (fe.device_type == DeviceType.CPU and not fe.is_async and
fe.id in cuda_corr_map):
for f_evt in cuda_corr_map[fe.id]:
if f_evt.device_type == DeviceType.CUDA:
fe.append_kernel(
f_evt.name,
f_evt.device_index,
f_evt.time_range.end - f_evt.time_range.start)
elif f_evt.device_type == DeviceType.CPU:
# make sure that 'thread' of a CPU Kineto (e.g. CUDA Runtime) event is associated
# with the 'thread' of the corresponding linked PyTorch event to properly track
# parents and children
f_evt.thread = fe.thread
def createFunctionEventForMemoryEvents(evt):
rel_start_us = evt.start_us() - trace_start_us
fe = FunctionEvent(
id=max_evt_id,
name=evt.name(),
trace_name=None, # not outputting in the trace
thread=evt.start_thread_id(),
start_us=rel_start_us,
end_us=rel_start_us, # no duration
fwd_thread=evt.start_thread_id(),
input_shapes=[],
stack=[],
scope=0, # RecordScope::FUNCTION
cpu_memory_usage=_cpu_memory_usage(evt),
cuda_memory_usage=_cuda_memory_usage(evt),
is_async=False,
sequence_nr=-1,
device_type=DeviceType.CPU,
device_index=0,
)
return fe
# output top-level memory events
for mem_record in mem_records:
if not mem_record[1]:
max_evt_id += 1
fe = createFunctionEventForMemoryEvents(mem_record[0])
function_events.append(fe)
for oom_record in oom_records:
max_evt_id += 1
fe = createFunctionEventForMemoryEvents(oom_record)
function_events.append(fe)
function_events.sort(key=lambda evt: [evt.time_range.start, -evt.time_range.end])
return function_events
class record_function(_ContextDecorator):
"""Context manager/function decorator that adds a label to a block of
Python code (or function) when running autograd profiler. It is
useful when tracing the code profile.
Args:
name (str): Label assigned to the block of code.
node_id (int): ID of node, for distributed profiling. Unset in
non-distributed cases.
Example:
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_AUTOGRAD_PROFILER)
>>> x = torch.randn((1, 1), requires_grad=True)
>>> with torch.autograd.profiler.profile() as prof:
... y = x ** 2
... with torch.autograd.profiler.record_function("label-z"): # label the block
... z = y ** 3
... y.backward()
...
>>> # xdoctest: +IGNORE_WANT
>>> # NOTE: some columns were removed for brevity
>>> print(prof.key_averages().table(sort_by="self_cpu_time_total"))
----------------------------------- --------------- --------------- ---------------
Name Self CPU total % CPU time avg Number of Calls
----------------------------------- --------------- --------------- ---------------
pow 60.77% 47.470us 3
mul 21.73% 25.465us 2
PowBackward0 12.03% 121.891us 1
torch::autograd::AccumulateGrad 2.70% 6.324us 1
label-z 2.13% 12.421us 1
torch::autograd::GraphRoot 0.64% 1.503us 1
----------------------------------- --------------- --------------- ---------------
Self CPU time total: 234.344us
CUDA time total: 0.000us
"""
def __init__(self, name: str, args: Optional[str] = None):
self.name: str = name
self.args: Optional[str] = args
# Whether or not we should run record function's end callbacks when exiting.
self.run_callbacks_on_exit: bool = True
# TODO: TorchScript ignores standard type annotation here
# self.record: Optional["torch.classes.profiler._RecordFunction"] = None
self.record = torch.jit.annotate(Optional["torch.classes.profiler._RecordFunction"], None)
def __enter__(self):
self.record = torch.ops.profiler._record_function_enter_new(self.name, self.args)
return self
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any):
if not self.run_callbacks_on_exit:
return
# Local variable is needed by TorchScript to refine Optional[T] to T
record = self.record
assert record is not None
# TODO: Too slow with __torch_function__ handling enabled
# See https://github.com/pytorch/pytorch/issues/76410
if not torch.jit.is_scripting():
with torch._C.DisableTorchFunctionSubclass():
torch.ops.profiler._record_function_exit._RecordFunction(record)
else:
torch.ops.profiler._record_function_exit(record)
def _call_end_callbacks_on_future(self, fut: Future[Any]) -> Future[Any]:
"""
_call_end_callbacks_on_future is meant to be used for profiling async
calls that return a future. Calling this function will extend recording
beyond this scope, until the future is satisfied. It is useful for profiling
the end to end time of asynchronous calls. This function should only be called
once to attach the callback onto the future, and will throw if called multiple
times.
Args:
fut: (torch._C.Future): future for which to schedule
callback for.
Returns:
A future that completes with the value of the passed in future when
the profiling callbacks have ran.
"""
# Throw if we have already attached a callback onto the future.
if not self.run_callbacks_on_exit:
raise RuntimeError("_call_end_callbacks_on_future can only be called once.")
# We are scheduling to run this RecordFunction's end callbacks when the
# passed in future completes, so don't run end callbacks on exit.
self.run_callbacks_on_exit = False
# Local variable is needed by TorchScript to refine Optional[T] to T
record = self.record
assert record is not None
# TODO: Too slow with __torch_function__ handling enabled
# See https://github.com/pytorch/pytorch/issues/76410
if not torch.jit.is_scripting():
with torch._C.DisableTorchFunctionSubclass():
profiled_future = torch.ops.profiler._call_end_callbacks_on_jit_fut._RecordFunction(
record, fut)
else:
profiled_future = torch.ops.profiler._call_end_callbacks_on_jit_fut(record, fut)
return profiled_future
[docs]class emit_itt:
"""Context manager that makes every autograd operation emit an ITT range.
It is useful when running the program under Intel(R) VTune Profiler::
vtune <--vtune-flags> <regular command here>
The Instrumentation and Tracing Technology (ITT) API enables your application to generate and
control the collection of trace data during its execution across different Intel tools.
This context manager is to annotate Intel(R) VTune Profiling trace. With help of this context manager,
you will be able to see labled ranges in Intel(R) VTune Profiler GUI.
.. warning:
This context manager should not be called recursively, i.e. at most one
instance should be enabled at any given time.
Args:
enabled (bool, optional): Setting ``enabled=False`` makes this context manager a no-op.
Default: ``True``.
record_shapes (bool, optional): If ``record_shapes=True``, the itt range wrapping
each autograd op will append information about the sizes of Tensor arguments received
by that op, in the following format:
``[[arg0.size(0), arg0.size(1), ...], [arg1.size(0), arg1.size(1), ...], ...]``
Non-tensor arguments will be represented by ``[]``.
Arguments will be listed in the order they are received by the backend op.
Please note that this order may not match the order in which those arguments were passed
on the Python side. Also note that shape recording may increase the overhead of itt range creation.
Default: ``False``
Example:
>>> # xdoctest: +SKIP("Undefined variables")
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_AUTOGRAD_PROFILER)
>>> with torch.autograd.profiler.emit_itt():
... model(x)
"""
def __init__(self, enabled=True, record_shapes=False):
self.enabled = enabled
self.entered = False
self.record_shapes = record_shapes
def __enter__(self):
if not self.enabled:
return
if self.entered:
raise RuntimeError("ITT annotation context manager is not reentrant")
self.entered = True
_enable_profiler(
ProfilerConfig(
ProfilerState.ITT,
self.record_shapes,
False,
False,
False,
False,
_ExperimentalConfig()),
set()
)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if not self.enabled:
return
_disable_profiler()
return False
[docs]class emit_nvtx:
"""Context manager that makes every autograd operation emit an NVTX range.
It is useful when running the program under nvprof::
nvprof --profile-from-start off -o trace_name.prof -- <regular command here>
Unfortunately, there's no way to force nvprof to flush the data it collected
to disk, so for CUDA profiling one has to use this context manager to annotate
nvprof traces and wait for the process to exit before inspecting them.
Then, either NVIDIA Visual Profiler (nvvp) can be used to visualize the timeline, or
:func:`torch.autograd.profiler.load_nvprof` can load the results for inspection
e.g. in Python REPL.
.. warning:
This context manager should not be called recursively, i.e. at most one
instance should be enabled at any given time.
Args:
enabled (bool, optional): Setting ``enabled=False`` makes this context manager a no-op.
Default: ``True``.
record_shapes (bool, optional): If ``record_shapes=True``, the nvtx range wrapping
each autograd op will append information about the sizes of Tensor arguments received
by that op, in the following format:
``[[arg0.size(0), arg0.size(1), ...], [arg1.size(0), arg1.size(1), ...], ...]``
Non-tensor arguments will be represented by ``[]``.
Arguments will be listed in the order they are received by the backend op.
Please note that this order may not match the order in which those arguments were passed
on the Python side. Also note that shape recording may increase the overhead of nvtx range creation.
Default: ``False``
Example:
>>> # xdoctest: +SKIP("undefined variables")
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_AUTOGRAD_PROFILER)
>>> with torch.cuda.profiler.profile():
... model(x) # Warmup CUDA memory allocator and profiler
... with torch.autograd.profiler.emit_nvtx():
... model(x)
**Forward-backward correlation**
When viewing a profile created using :class:`emit_nvtx` in the Nvidia Visual Profiler,
correlating each backward-pass op with the corresponding forward-pass op can be difficult.
To ease this task, :class:`emit_nvtx` appends sequence number information to the ranges it
generates.
During the forward pass, each function range is decorated with ``seq=<N>``. ``seq`` is a running
counter, incremented each time a new backward Function object is created and stashed for backward.
Thus, the ``seq=<N>`` annotation associated with each forward function range tells you that
if a backward Function object is created by this forward function,
the backward object will receive sequence number N.
During the backward pass, the top-level range wrapping each C++ backward Function's
``apply()`` call is decorated with ``stashed seq=<M>``. ``M`` is the sequence number that
the backward object was created with. By comparing ``stashed seq`` numbers in backward with ``seq``
numbers in forward, you can track down which forward op created each backward Function.
Any functions executed during the backward pass are also decorated with ``seq=<N>``. During
default backward (with ``create_graph=False``) this information is irrelevant, and in fact,
``N`` may simply be 0 for all such functions. Only the top-level ranges associated with
backward Function objects' ``apply()`` methods are useful, as a way to correlate these Function
objects with the earlier forward pass.
**Double-backward**
If, on the other hand, a backward pass with ``create_graph=True`` is underway (in other words,
if you are setting up for a double-backward), each function's execution during backward
is given a nonzero, useful ``seq=<N>``. Those functions may themselves create Function objects
to be executed later during double-backward, just as the original functions in the forward pass did.
The relationship between backward and double-backward is conceptually the same as the relationship
between forward and backward: The functions still emit current-sequence-number-tagged ranges,
the Function objects they create still stash those sequence numbers, and during the eventual
double-backward, the Function objects' ``apply()`` ranges are still tagged with ``stashed seq``
numbers, which can be compared to `seq` numbers from the backward pass.
.. warning:
The sequence number is thread-local, and some forward functions don't create an associated
backward Function object (instead delegating that to sub-functions further down the call chain).
For these reasons, the correspondence of stashed sequence numbers in
backward Function ``apply()`` ranges with `seq` numbers in forward-pass ranges is
not guaranteed to be 1 to 1. The sequence numbers alone may not be enough to fully
disambiguate which forward function created which
backward Function object. You may need to make a judgment based on analytic knowledge of what
the expected correspondence should be.
"""
def __init__(self, enabled=True, record_shapes=False):
self.enabled = enabled
self.entered = False
self.record_shapes = record_shapes
def __enter__(self):
if not self.enabled:
return
if self.entered:
raise RuntimeError("NVTX annotation context manager is not reentrant")
self.entered = True
torch.cuda.synchronize()
_enable_profiler(
ProfilerConfig(
ProfilerState.NVTX,
self.record_shapes,
False,
False,
False,
False,
_ExperimentalConfig()),
set()
)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if not self.enabled:
return
torch.cuda.synchronize()
_disable_profiler()
return False
[docs]def load_nvprof(path):
"""Opens an nvprof trace file and parses autograd annotations.
Args:
path (str): path to nvprof trace
"""
return EventList(parse_nvprof_trace(path))
class EnforceUnique:
"""Raises an error if a key is seen more than once."""
def __init__(self):
self.seen = set()
def see(self, *key):
if key in self.seen:
raise RuntimeError('duplicate key: ' + str(key))
self.seen.add(key)
def parse_nvprof_trace(path):
import sqlite3
conn = sqlite3.connect(path)
conn.row_factory = sqlite3.Row
# Parse strings table
strings = {}
for r in conn.execute("SELECT _id_ as id, value FROM StringTable"):
strings[r["id"]] = torch._C._demangle(r["value"])
# First, find all functions and create FunctionEvents for them
marker_query = """
SELECT
start.id AS marker_id, start.name, start.timestamp AS start_time, end.timestamp AS end_time
FROM
CUPTI_ACTIVITY_KIND_MARKER AS start INNER JOIN CUPTI_ACTIVITY_KIND_MARKER AS end
ON start.id = end.id
WHERE
start.name != 0 AND end.name = 0
"""
functions = []
functions_map = {}
unique = EnforceUnique()
for row in conn.execute(marker_query):
unique.see(row['marker_id'])
evt = FunctionEvent(id=row['marker_id'],
node_id=0, # missing a node_id when calling FunctionEvent. This is just to ensure
# that pytorch doesn't crash when creating a FunctionEvent() object
name=strings[row['name']],
start_us=row['start_time'],
end_us=row['end_time'],
thread=0) # TODO: find in sqlite database
functions.append(evt)
functions_map[evt.id] = evt
# Now, correlate all kernels with FunctionEvents
kernel_query = """
SELECT
start.id AS marker_id, start.name, start.timestamp, end.timestamp,
runtime._id_ AS runtime_id, runtime.cbid, runtime.start AS runtime_start, runtime.end AS runtime_end,
kernel.start AS kernel_start, kernel.end AS kernel_end, kernel.name AS kernel_name
FROM
CUPTI_ACTIVITY_KIND_MARKER AS start
INNER JOIN CUPTI_ACTIVITY_KIND_MARKER AS end
ON start.id = end.id
INNER JOIN CUPTI_ACTIVITY_KIND_RUNTIME as runtime
ON (start.timestamp < runtime.start AND runtime.end < end.timestamp)
INNER JOIN CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL AS kernel
ON kernel.correlationId = runtime.correlationId
"""
unique = EnforceUnique()
for row in conn.execute(kernel_query):
unique.see(row['marker_id'], row['runtime_id'])
# 211 is cudaKernelLaunch for cuda >= 9.2
assert (row['cbid'] == 211)
evt = functions_map[row['marker_id']]
evt.append_kernel(row['kernel_name'],
0,
row['kernel_end'] - row['kernel_start'])
functions.sort(key=lambda evt: evt.time_range.start)
return functions
class KinetoStepTracker:
"""Provides an abstraction for incrementing the step count globally.
Previously, we only had one place to mark that a step() has occurred
in the program via pytorch profiler step(). We will now add step hooks
in the Optimizer class https://github.com/pytorch/pytorch/issues/88446
- This could mean programs that already call profiler.step() every
iteration can end up double incrementing step count.
- If a model uses multiple optimizers we can also have double or more
counting of the step.
We fix this by adding a layer of abstraction before calling step()
to the kineto library. The idea is to maintain steps per requester in a dict:
```
{
"ProfilerStep": 100, # triggered by profiler step() call
"Optimizer1Step": 100, # Optimizer 1 or 2 are just examples, could be SGD, Adam etc
"Optimizer2Step": 100,
}
```
To figure out the global step count just take the max of dict values (100).
If one of the count increments the max will go up.
```
{
"ProfilerStep": 100,
"Optimizer1Step": 101, # Optimizer1 got incremented first say
"Optimizer2Step": 100,
}
```
Then global step count is 101
We only call the kineto step() function when global count increments.
NOTE: Please do not use the KinetoStepTracker in modules beside the Optimizer
for now. The result could be incorrect increments of the step count.
"""
_current_step = -1
_step_dict: Dict[str, int] = defaultdict(int)
@classmethod
def init_step_count(cls, requester: str):
cls._step_dict[requester] = cls._current_step
@classmethod
def erase_step_count(cls, requester: str) -> bool:
return cls._step_dict.pop(requester, None) is not None
@classmethod
def increment_step(cls, requester: str) -> int:
"""Increments the step count for the requester.
Additionally if the max over all step counts has incremented then
trigger the _kineto_step()
returns global step count
"""
if requester not in cls._step_dict:
cls.init_step_count(requester)
cls._step_dict[requester] += 1
new_step = max(cls._step_dict.values())
if new_step > cls._current_step:
delta = new_step - cls._current_step
if delta > 1:
warn("Profiler step count has increased more than 1 - "
f"current_step = {cls._current_step} step dict = {cls._step_dict}")
for _ in range(0, delta):
_kineto_step()
cls._current_step = new_step
return cls._current_step
@classmethod
def current_step(cls) -> int:
return cls._current_step


Saint of Light Agnes:
I've heard of your devotion. Goddard Castle Town needs someone to help relieve the grief and suffering here. The people have lost all hope!
Can you help me to reignite their passions?
"What can I do?"


 Or the guy had an appointment. Or...who knows? Without more information, it's a waste of time trying to figure out what happened. |
|
| Aug-27-07 | | PAWNTOEFOUR: <keypusher>......i know that....i was just curious as to how the position might evolve.....but that's a good idea......a shredder that can talk.....i'll have to work on that |
|
| Aug-27-07 | | PAWNTOEFOUR: after 63:07 and 1,077,977,271 nodes,shredder comes up with this......9.e5 10.d5 Nd4 11.0-0 Nxc2 12.Qxc2 Bd7 13. Be3 and evaluates it @+0.16...looks pretty even to me,i could be wrong........i usually am |
|
| Aug-27-07 | | nimzo knight: Is 4. Bd3 the best continuation here. People often put the trap of 4. Be2 Nxe4 5. Qa4+. |
|
| Aug-28-07 | | savagerules: Obviously Gary was aware of Charambalos reputation with the Dragon Sicilian and so he played the anti-patzer Sicilian with White and Black got offended and left in a huff. |
|
| Aug-28-07 | | pacelli: Actually black suffered a mild heart attack and the game stopped - it was widely reported in the Spanish dailies back then, I remember. |
|
| Aug-29-07 | | Jack Kerouac: Heart attack! Couldn't Kaspy at least give him a pass?
Although Reshevsky would take the win.... |
|
| Feb-13-08 | | medo78: I think black just wanna get in history by shortest game against kasparov ,,,, thats why we cee his game here !!! |
|
| Jun-25-08 | | zoat22: Did Kasparov actually play the KOPEC System?!?!?!?!?! |
|
| Aug-12-08 | | dumbgai: 9. Nc3!! A brilliant winning move that only a genius like Kasparov could find! Actually I hate to say it but I had this exact position as white in a blitz game today and I lost horribly. |
|
| Apr-09-09 | | WhiteRook48: what kind of resignation is this?? |
|
| Oct-31-09 | | WhiteRook48: this game actually continued 9...Qb6 10 d5! Ne5 11 Bf4!! |
|
| Oct-31-09 | | WhiteRook48: btw 4 Bd3 seems to be completely against Kasparov's principles.
(and no the game did not continue) |
|
| Mar-11-10 | | hedgeh0g: My guess is that Kasparov was masquerading as someone else and when he revealed his true identity, Charambalos decided to do the logical thing. |
|
Jun-28-10
| | FSR: 9.Nc3 is a good move, but it doesn't warrant a heart attack by Black. |
|
| Oct-13-16 | | Al2009: He suddenly remembered he left his car without parking disk! |
|
|
|
< Earlier Kibitzing · PAGE 2 OF 2 ·
Later Kibitzing> |


--- layout: post title: "Builder as a monoid" description: "Builder, particularly Fluent Builder, is one of the more useful design patterns. Here's why." date: 2020-02-17 7:18 UTC tags: [Software Design, Design Patterns] image: "/content/binary/double-step-endomorphism.png" image_alt: "An object (a little circle) to the left, going into two horizontally oriented pipe, on after the other, and coming out to the right in a different colour." --- {% include JB/setup %}
{{ page.description }}
This article is part of a series of articles about design patterns and their universal abstraction counterparts.
The Builder design pattern is an occasionally useful pattern, but mostly in its Fluent Builder variation. I've already described that Builder, Fluent Builder, and Immutable Fluent Builder are isomorphic. The Immutable Fluent Builder variation is a set of pure functions, so among the three variations, it best fits the set of universal abstractions that I've so far discussed in this article series.
Design Patterns describes 23 patterns. Some of these are more useful than others. I first read the book in 2003, and while I initially used many of the patterns, after some years I settled into a routine where I'd reach for the same handful of patterns and ignore the rest.
What makes some design patterns more universally useful than others? There's probably components of both subjectivity and chance, but I also believe that there's some correlation to universal abstractions. I consider abstractions universal when they are derived from universal truths (i.e. mathematics) instead of language features or 'just' experience. That's what the overall article series is about. In this article, you'll learn how the Builder pattern is an instance of a universal abstraction. Hopefully, this goes a long way towards explaining why it seems to be so universally useful.
I'll start with the HttpRequestMessageBuilder
from the article about Builder isomorphisms, particularly its Immutable Fluent Builder incarnation. Start by isolating those methods that manipulate the Builder. These are the functions that had void
return types in the original Builder incarnation. Imagine, for example, that you extract an interface of only those methods. What would such an interface look like?
public interface IHttpRequestMessageBuilder { HttpRequestMessageBuilder AddJsonBody(object jsonBody); HttpRequestMessageBuilder WithMethod(HttpMethod newMethod); }
Keep in mind that on all instance methods, the instance itself can be viewed as 'argument 0'. In that light, each of these methods take two arguments: a Builder and the formal argument (jsonBody
and newMethod
, respectively). Each method returns a Builder. I've already described how this is equivalent to an endomorphism. An endomorphism is a function that returns the same type of output as its input, and it forms a monoid.
This can be difficult to see, so I'll make it explicit. The code that follows only exists to illustrate the point. In no way do I endorse that you write code in this way.
You can define a formal interface for an endomorphism:
public interface IEndomorphism<T> { T Run(T x); }
Notice that it's completely generic. The Run
method takes a value of the generic type T
and returns a value of the type T
. The identity of the monoid, you may recall, is the eponymously named identity function which returns its input without modification. You can also define the monoidal combination of two endomorphisms:
public class AppendEndomorphism<T> : IEndomorphism<T> { private readonly IEndomorphism<T> morphism1; private readonly IEndomorphism<T> morphism2; public AppendEndomorphism(IEndomorphism<T> morphism1, IEndomorphism<T> morphism2) { this.morphism1 = morphism1; this.morphism2 = morphism2; } public T Run(T x) { return morphism2.Run(morphism1.Run(x)); } }
This implementation of IEndomorphism<T>
composes two other IEndomorphism<T>
objects. When its Run
method is called, it first calls Run
on morphism1
and then uses the return value of that method call (still a T
object) as input for Run
on morphism2
.
If you need to combine more than two endomorphisms then that's also possible, because monoids accumulate.
You can adapt the WithMethod
method to the IEndomorphism<HttpRequestMessageBuilder>
interface:
public class ChangeMethodEndomorphism : IEndomorphism<HttpRequestMessageBuilder> { private readonly HttpMethod newMethod; public ChangeMethodEndomorphism(HttpMethod newMethod) { this.newMethod = newMethod; } public HttpRequestMessageBuilder Run(HttpRequestMessageBuilder x) { if (x is null) throw new ArgumentNullException(nameof(x)); return x.WithMethod(newMethod); } }
In itself, this is simple code, but it does turn things on their head. The newMethod
argument is now a class field (and constructor argument), while the HttpRequestMessageBuilder
has been turned into a method argument. Keep in mind that I'm not doing this because I endorse this style of API design; I do it to demonstrate how the Immutable Fluent Builder pattern is an endomorphism.
Since ChangeMethodEndomorphism
is an Adapter between IEndomorphism<HttpRequestMessageBuilder>
and the WithMethod
method, I hope that this is becoming apparent. I'll show one more Adapter.
In the example code, there's one more method that modifies an HttpRequestMessageBuilder
object, and that's the AddJsonBody
method. You can also create an Adapter over that method:
public class AddJsonBodyEndomorphism : IEndomorphism<HttpRequestMessageBuilder> { private readonly object jsonBody; public AddJsonBodyEndomorphism(object jsonBody) { this.jsonBody = jsonBody; } public HttpRequestMessageBuilder Run(HttpRequestMessageBuilder x) { if (x is null) throw new ArgumentNullException(nameof(x)); return x.AddJsonBody(jsonBody); } }
While the AddJsonBody
method itself is more complicated than WithMethod
, the Adapter is strikingly similar.
You can use the IEndomorphism<T>
API to compose a pipeline of operations that will, for example, make an HttpRequestMessageBuilder
build an HTTP POST
request with a JSON body:
IEndomorphism<HttpRequestMessageBuilder> morphism = new AppendEndomorphism<HttpRequestMessageBuilder>( new ChangeMethodEndomorphism(HttpMethod.Post), new AddJsonBodyEndomorphism(new { id = Guid.NewGuid(), date = "2020-03-22 19:30:00", name = "Ælfgifu", email =<EMAIL_ADDRESS>quantity = 1 }));
You can then Run
the endomorphism over a new HttpRequestMessageBuilder
object to produce an HTTP request:
HttpRequestMessage msg = morphism.Run(new HttpRequestMessageBuilder(url)).Build();
The msg
object represents an HTTP POST
request with the supplied JSON body.
Once again, I stress that the purpose of this little exercise is only to demonstrate how an Immutable Fluent Builder is an endomorphism, which is a monoid.
You can give Test Data Builders the same treatment, again only to demonstrate that the reason they compose so well is because they're monoids. I'll use an immutable variation of the AddressBuilder
from this article.
For example, to modify a city, you can introduce an endomorphism like this:
public class CityEndomorphism : IEndomorphism<AddressBuilder> { private readonly string city; public CityEndomorphism(string city) { this.city = city; } public AddressBuilder Run(AddressBuilder x) { return x.WithCity(city); } }
You can use it to create an address in Paris like this:
IEndomorphism<AddressBuilder> morphism = new CityEndomorphism("Paris"); Address address = morphism.Run(new AddressBuilder()).Build();
The address
is fully populated with Street
, PostCode
, and so on, but apart from City
, you know none of the values.
Let's return to the question from the introduction to the article. What makes some design patterns useful? I don't think that there's a single answer to that question, but I find it intriguing that so many of the useful patterns turn out to be equivalent to universal abstractions. The Builder pattern is a monoid. From a programming perspective, the most useful characteristic of semigroups and monoids is that they enable you to treat many objects as one object. Monoids compose.
Of the three Builder variations, the Immutable Fluent Builder is the most useful. It's also the variation that most clearly corresponds to the endomorphism monoid. Viewing it as an endomorphism reveals its strengths. When or where is a Builder most useful?
Don't be mislead by Design Patterns, which states the intent of the Builder pattern like this:
This may still be the case, but I don't find that this is the primary advantage offered by the pattern. We've learned much about the utility of each design pattern since 1994, so I don't blame the Gang of Four for not seeing this. I do think, however, that it's important to emphasise that the benefit you can derive from a pattern may differ from the original motivation."Separate the construction of a complex object from its representation so that the same construction process can create different representations."
An endomorphism represents a modification of a value. You need a value to get started, and you get a modified value (of the same type) as output.
Sometimes, all you need is the initial object.
And sometimes, you need to compose several changes.
To me, this makes the sweet spot for the pattern clear. Use an (Immutable) Fluent Builder when you have a basic object that's useful in itself, but where you want to give client code the option to make changes to the defaults.
Sometimes, the initial object has self-contained default values. Test Data Builders are good examples of that:
public AddressBuilder() { this.street = ""; this.city = ""; this.postCode = new PostCodeBuilder().Build(); }
The AddressBuilder
constructor fully initialises the object. You can use its WithNoPostcode
, WithStreet
, etcetera methods to make changes to it, but you can also use it as is.
In other cases, client code must initialise the object to be built. The HttpRequestMessageBuilder
is an example of that:
public HttpRequestMessageBuilder(string url) : this(new Uri(url)) { } public HttpRequestMessageBuilder(Uri url) : this(url, HttpMethod.Get, null) { } private HttpRequestMessageBuilder(Uri url, HttpMethod method, object? jsonBody) { this.url = url; Method = method; this.jsonBody = jsonBody; }
While there's more than one constructor overload, client code must supply a url
in one form or other. That's the precondition of this class. Given a valid url
, though, an HttpRequestMessageBuilder
object can be useful without further modification, but you can also modify it by calling its methods.
You often see the Builder pattern used for configuration APIs. The ASP.NET Core IApplicationBuilder is a prominent example of the Fluent Builder pattern. The NServiceBus endpoint configuration API, on the other hand, is based on the classic Builder pattern. It makes sense to use an endomorphic design for framework configuration. Framework designers want to make it as easy to get started with their framework as possible. For this reason, it's important to provide a useful default configuration, so that you can get started with as little ceremony as possible. On the other hand, a framework must be flexible. You need a way to tweak the configuration to support your particular needs. The Builder pattern supports both scenarios.
Other examples include Test Data Builders, as well as specialised Builders such as UriBuilder and SqlConnectionStringBuilder.
It's also worth noting that F# copy-and-update expressions are endomorphisms. That's the reason that when you have immutable records, you need no Test Data Builders.
The Builder pattern comes in (at least) three variations: the Gang-of-Four Builder pattern, Fluent Builder, and Immutable Fluent Builder. All are isomorphic to each other, and are equivalent to the endomorphism monoid.
Viewing Builders as endomorphisms may mostly be an academic exercise, but I think it highlights the sweet spot for the pattern. It's particularly useful when you wish to expose an API that offers simple defaults, while at the same time enabling client code to make changes to those defaults. When those changes involve several steps (as e.g. AddJsonBody
) you can view each modifier method as a Facade.
Next: Visitor as a sum type.


- New: Added VisualBoyAdvance(-M) emulator profile
- New: Added "Clear web cache" button into settings (to help with account linking issues)
- Fix: Issues using Model 2 Emulator
- Fix: Filters are not working properly for entries with spaces
- Fix: Emulator Import doesn't recognize 64bit version of snes9x
- Fix: Crash when starting game via jump list
- Fix: Crash when setting game category
- Fix: Crash when loading image from DB


Congratulations on creating your brand!
Depending on the package you purchased, there are different file formats of your logo in this download:
-
Basic Package: PNG file
- Premium and Enterprise Packages: PNG, SVG, EPS, PDF files
Using your files
Here’s a quick breakdown of where and how to use your files:
Online
If you’re using your logo for any digital purpose — from PowerPoint presentations to social media profiles — choose PNG files.
If you’re sending your logo to be printed on business cards, brochures, clothing, and more, provide the printer with a PDF or EPS. If the print is more technical and requires edits from the printer, send vector files (SVG or EPS).
Sending to a Designer
If you’re sending your logo to a designer to make changes, use SVG or EPS files unless they request otherwise.
Sharing
When sharing a logo file, send a PDF or PNG, as they’re easy-to-read file formats.
Resizing
Don’t see all of the file sizes you need? Use this website to adjust the file sizes of your PNG logo.
Your Logo Font and Colors
Fonts
Croogla Bold
Colors
Add-ons
Want more help with your branding? Get business card designs, a social media kit, or have your logo tweaked by one of our pro designers. Here’s how to purchase add-ons:
- Log in to your account and click your purchased logo
- In the top right-hand corner, click Purchase Add-ons
- Select the add-ons you’d like, then click Continue to check out
- Complete your purchase (you’ll only pay for the add-ons, not your logo!)
Learn more about our package add-ons here.
If you have any questions about your logo, Email Support
Happy business-building!


Viral Shah was born in Borsad, a town in Gujarat, India. He finished his primary and higher secondary education in Borsad. For higher education, he moved to Vallabh Vidya Nagar. As a boy he always wanted to be an engineer or chartered accountant, so he joined bachelor of computer application at semcom college in 2010. During his bachelor he was interested in Computers, particularly, in web desiging and mobile app desiging. In his third years of bachelor he did several project as a part of academics. He achieved Bachelors of Computer Application in 2013.
Then he worked for local company "GeekyWays Pvt Ltd". Where he learned about more interesting stuff like desiging web application and Testing application(manually). His job as a Junior Software Developer involved maintaining, testing, and documenting existing software products.
In 2016, he left this job for higher studies. In September 2016, he enrolled in Mobile Application Design and Development at Lambton College, Toronto to learn more about Web and Mobile Development. Here, he got chance to work in groups for almost all subjects, and gained leadership experience. He also learned latest technologies such as Windows Communication Foundation (WCF), Android, and latest web development tools and frameworks. During this program he, made ecommerce android based application. Currently, he is in the last semester of the project, and he is working as Web Developer with Upzes and as Android Developer with Mobisix.


RULES!
- A random number is going to pop up at the bottom. Watch out!
- There are four crystals below. Each one is assigned a random number at the begining of the game. That number is hidden from you, unless you can do math.
- Click the Crystals to add to the number listed
- You win when the numbers match. Have fun nerd!
Lets get it!
Your Total Score Is:
0


Creating excellence more important than marks, says Mohan Bhagwat
by Nagpur Today, Nagpur NewsNagpur: RSS chief Mohan Bhagwat on Tuesday asked educationists to create excellence among students rather than having a classroom system geared towards
scoring marks in exams.
He was addressing the ‘International Principals’ Education Conference 2019′ here.
“Classroom education is not everything, though it has its importance. But the classroom is for real-time experience and how it can be taken forward to a conclusion,” Bhagwat said.
“Nowadays, marksheets and marks have become more important due to competition. Doing this (giving predominance to marks) is not education. We need to create people through excellence,” he said.


Description: Takes a function and returns a new one that will always have a particular context.
function: Function() The function whose context will be changed.
context: PlainObject
The object to which the context (this
) of the function should be set.
context: PlainObject The object to which the context of the function should be set.
name: String
The name of the function whose context will be changed (should be a property of the context
object).
This method is most useful for attaching event handlers to an element where the context is pointing back to a different object. Additionally, jQuery makes sure that even if you bind the function returned from jQuery.proxy()
it will still unbind the correct function if passed the original.
Be aware, however, that jQuery's event binding subsystem assigns a unique id to each event handling function in order to track it when it is used to specify the function to be unbound. The function represented by jQuery.proxy()
is seen as a single function by the event subsystem, even when it is used to bind different contexts. To avoid unbinding the wrong handler, use a unique event namespace for binding and unbinding (e.g., "click.myproxy1"
) rather than specifying the proxied function during unbinding.
<!DOCTYPE html>

<button type="button" id="test">Test</button>

<!DOCTYPE html>

<button id="test">Test</button>


|
Imperial College London
Imperial College London is a world top ten university with an international reputation for excellence in teaching and research. Consistently rated amongst the world's best universities, Imperial is committed to developing the next generation of researchers, scientists and academics through collaboration across disciplines. In one year the money for university is about £9,250. |
| School Subjects(Division) | |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Tuition and Expenses
| When tuition fees are paid by SLC to Imperial | How much is paid to Imperial |
| Star of Term 1 | 25% of tuition fee |
| Star of Term 2 | 25% of tuition fee |
| Star of Term 3 | 50% of tuition fee |
| Section | Average | 25th Percentile | 75th Percentile |
| Math | N/A | N/A | N/A |
| Reading | N/A | N/A | N/A |
| Composite | N/A | N/A | N/A |