From 3f51f48ee55690c7f64e591a729d9cb034264ca4 Mon Sep 17 00:00:00 2001 From: SAM <8dmasters@gmail.com> Date: Fri, 31 May 2024 10:00:10 +0530 Subject: [PATCH 01/47] Create Transformers.md Added a empty .md file to be served as a guide for Transformers --- contrib/machine-learning/Transformers.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 contrib/machine-learning/Transformers.md diff --git a/contrib/machine-learning/Transformers.md b/contrib/machine-learning/Transformers.md new file mode 100644 index 0000000..e69de29 From b832f8f0c90673462ecc990f45595761565b027d Mon Sep 17 00:00:00 2001 From: SAM <60264918+SAM-DEV007@users.noreply.github.com> Date: Fri, 31 May 2024 13:40:20 +0530 Subject: [PATCH 02/47] Update Transformers.md Added topics --- contrib/machine-learning/Transformers.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/contrib/machine-learning/Transformers.md b/contrib/machine-learning/Transformers.md index e69de29..7bcc102 100644 --- a/contrib/machine-learning/Transformers.md +++ b/contrib/machine-learning/Transformers.md @@ -0,0 +1,21 @@ +# Transformers +## Introduction +A transformer is a deep learning architecture developed by Google and based on the multi-head attention mechanism. It is based on the softmax-based attention +mechanism. Before transformers, predecessors of attention mechanism were added to gated recurrent neural networks, such as LSTMs and gated recurrent units (GRUs), which +processed datasets sequentially. Dependency on previous token computations prevented them from being able to parallelize the attention mechanism. + +## Key Concepts + +## Architecture + +## Implementation +### Theory +Text is converted to numerical representations called tokens, and each token is converted into a vector via looking up from a word embedding table. +At each layer, each token is then contextualized within the scope of the context window with other tokens via a parallel multi-head attention mechanism +allowing the signal for key tokens to be amplified and less important tokens to be diminished. + +### HuggingFace + +### Tensorflow and Keras + +### PyTorch From 5b3c8d7ad108d4a65b4a946d719d242fe9eae308 Mon Sep 17 00:00:00 2001 From: SAM <60264918+SAM-DEV007@users.noreply.github.com> Date: Fri, 31 May 2024 15:14:09 +0530 Subject: [PATCH 03/47] Update Transformers.md Added information about Model Architecture --- contrib/machine-learning/Transformers.md | 59 +++++++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/contrib/machine-learning/Transformers.md b/contrib/machine-learning/Transformers.md index 7bcc102..49a1b97 100644 --- a/contrib/machine-learning/Transformers.md +++ b/contrib/machine-learning/Transformers.md @@ -4,9 +4,53 @@ A transformer is a deep learning architecture developed by Google and based on t mechanism. Before transformers, predecessors of attention mechanism were added to gated recurrent neural networks, such as LSTMs and gated recurrent units (GRUs), which processed datasets sequentially. Dependency on previous token computations prevented them from being able to parallelize the attention mechanism. -## Key Concepts +## Model Architecture +

Model Architecture

-## Architecture +### Encoder +The encoder is composed of a stack of identical layers. Each layer has two sub-layers. The first is a multi-head self-attention mechanism, and the second is a simple, positionwise fully connected feed-forward network. Each encoder consists of two major components: a self-attention mechanism and a feed-forward neural network. The self-attention mechanism accepts input encodings from the previous encoder and weights their relevance to each other to generate output encodings. The feed-forward neural network further processes each output encoding individually. These output encodings are then passed to the next encoder as its input, as well as to the decoders. + +### Decoder +The decoder is also composed of a stack of identical layers. In addition to the two sub-layers in each encoder layer, the decoder inserts a third sub-layer, which performs multi-head attention over the output of the encoder stack. The decoder functions in a similar fashion to the encoder, but an additional attention mechanism is inserted which instead draws relevant information from the encodings generated by the encoders. This mechanism can also be called the encoder-decoder attention. + +### Attention +#### Scaled Dot-Product Attention +The input consists of queries and keys of dimension dk, and values of dimension dv. We compute the dot products of the query with all keys, divide each by √dk, and apply a softmax function to obtain the weights on the values. + +> Attention(Q, K, V) = softmax(QKT / √dk) * V + +#### Multi-Head Attention +Instead of performing a single attention function with dmodel-dimensional keys, values and queries, it is beneficial to linearly project the queries, keys and values h times with different, learned linear projections to dk, dk and dv dimensions, respectively. + +Multi-head attention allows the model to jointly attend to information from different representation +subspaces at different positions. With a single attention head, averaging inhibits this. + +> MultiHead(Q, K, V) = Concat(head1, ..., headh) * WO + +where, + +> headi = Attention(Q * WiQ, K * WiK, V * WiV) + +where the projections are parameter matrices. + +#### Masked Attention +It may be necessary to cut out attention links between some word-pairs. For example, the decoder for token position +𝑡 should not have access to token position 𝑡+1. + +> MaskedAttention(Q, K, V) = softmax(M + (QKT / √dk)) * V + +### Feed-Forward Network +Each of the layers in the encoder and decoder contains a fully connected feed-forward network, which is applied to each position separately and identically. This +consists of two linear transformations with a ReLU activation in between. +> FFN(x) = (max(0, (x * W1) + b1) * W2) + b2 + +### Positional Encoding +A positional encoding is a fixed-size vector representation that encapsulates the relative positions of tokens within a target sequence: it provides the transformer model with information about where the words are in the input sequence. + +The sine and cosine functions of different frequencies: +> PE(pos,2i) = sin(pos/100002i/dmodel) + +> PE(pos,2i+1) = cos(pos/100002i/dmodel) ## Implementation ### Theory @@ -19,3 +63,14 @@ allowing the signal for key tokens to be amplified and less important tokens to ### Tensorflow and Keras ### PyTorch + +## Application +The transformer has had great success in natural language processing (NLP). Many large language models such as GPT-2, GPT-3, GPT-4, Claude, BERT, XLNet, RoBERTa and ChatGPT demonstrate the ability of transformers to perform a wide variety of such NLP-related tasks, and have the potential to find real-world applications. + +These may include: +- Machine translation +- Document summarization +- Text generation +- Biological sequence analysis +- Computer code generation +- Video analysis From 35357d2fe3f6650faca3d0f19327fe4fa7e8629d Mon Sep 17 00:00:00 2001 From: SAM <60264918+SAM-DEV007@users.noreply.github.com> Date: Fri, 31 May 2024 17:04:07 +0530 Subject: [PATCH 04/47] Update Transformers.md Added Tensorflow implementation --- contrib/machine-learning/Transformers.md | 136 ++++++++++++++++++++++- 1 file changed, 134 insertions(+), 2 deletions(-) diff --git a/contrib/machine-learning/Transformers.md b/contrib/machine-learning/Transformers.md index 49a1b97..a5a56ec 100644 --- a/contrib/machine-learning/Transformers.md +++ b/contrib/machine-learning/Transformers.md @@ -58,12 +58,144 @@ Text is converted to numerical representations called tokens, and each token is At each layer, each token is then contextualized within the scope of the context window with other tokens via a parallel multi-head attention mechanism allowing the signal for key tokens to be amplified and less important tokens to be diminished. -### HuggingFace +### Tensorflow +Tensorflow provides the transformer encoder and decoder block that can be implemented by the specification of the user. Although, the transformer is not provided as a standalone to be imported and executed, the user has to create the model first. They also have a tutorial on how to implement the transformer from scratch for machine translation and can be found [here](https://www.tensorflow.org/text/tutorials/transformer). -### Tensorflow and Keras +More information on [encoder](https://www.tensorflow.org/api_docs/python/tfm/nlp/layers/TransformerEncoderBlock) and [decoder](https://www.tensorflow.org/api_docs/python/tfm/nlp/layers/TransformerDecoderBlock) block mentioned in the code. + +Imports: +``` +import tensorflow as tf +import tensorflow_models as tfm +``` + +Adding word embeddings and positional encoding: +``` +class PositionalEmbedding(tf.keras.layers.Layer): + def __init__(self, vocab_size, d_model): + super().__init__() + self.d_model = d_model + self.embedding = tf.keras.layers.Embedding(vocab_size, d_model, mask_zero=True) + self.pos_encoding = tfm.nlp.layers.RelativePositionEmbedding(hidden_size=d_model) + + def compute_mask(self, *args, **kwargs): + return self.embedding.compute_mask(*args, **kwargs) + + def call(self, x): + length = tf.shape(x)[1] + x = self.embedding(x) + x = x + self.pos_encoding[tf.newaxis, :length, :] + return x +``` + +Creating the encoder for the transformer: +``` +class Encoder(tf.keras.layers.Layer): + def __init__(self, num_layers, d_model, num_heads, + dff, vocab_size, dropout_rate=0.1): + super().__init__() + + self.d_model = d_model + self.num_layers = num_layers + + self.pos_embedding = PositionalEmbedding( + vocab_size=vocab_size, d_model=d_model) + + self.enc_layers = [ + tfm.nlp.layers.TransformerEncoderBlock(output_last_dim=d_model, + num_attention_heads=num_heads, + inner_dim=dff, + inner_activation="relu", + inner_dropout=dropout_rate) + for _ in range(num_layers)] + self.dropout = tf.keras.layers.Dropout(dropout_rate) + + def call(self, x): + x = self.pos_embedding(x, length=2048) + x = self.dropout(x) + + for i in range(self.num_layers): + x = self.enc_layers[i](x) + + return x +``` + +Creating the decoder for the transformer: +``` +class Decoder(tf.keras.layers.Layer): + def __init__(self, num_layers, d_model, num_heads, dff, vocab_size, + dropout_rate=0.1): + super(Decoder, self).__init__() + + self.d_model = d_model + self.num_layers = num_layers + + self.pos_embedding = PositionalEmbedding(vocab_size=vocab_size, + d_model=d_model) + self.dropout = tf.keras.layers.Dropout(dropout_rate) + self.dec_layers = [ + tfm.nlp.layers.TransformerDecoderBlock(num_attention_heads=num_heads, + intermediate_size=dff, + intermediate_activation="relu", + dropout_rate=dropout_rate) + for _ in range(num_layers)] + + def call(self, x, context): + x = self.pos_embedding(x) + x = self.dropout(x) + + for i in range(self.num_layers): + x = self.dec_layers[i](x, context) + + return x +``` + +Combining the encoder and decoder to create the transformer: +``` +class Transformer(tf.keras.Model): + def __init__(self, num_layers, d_model, num_heads, dff, + input_vocab_size, target_vocab_size, dropout_rate=0.1): + super().__init__() + self.encoder = Encoder(num_layers=num_layers, d_model=d_model, + num_heads=num_heads, dff=dff, + vocab_size=input_vocab_size, + dropout_rate=dropout_rate) + + self.decoder = Decoder(num_layers=num_layers, d_model=d_model, + num_heads=num_heads, dff=dff, + vocab_size=target_vocab_size, + dropout_rate=dropout_rate) + + self.final_layer = tf.keras.layers.Dense(target_vocab_size) + + def call(self, inputs): + context, x = inputs + + context = self.encoder(context) + x = self.decoder(x, context) + logits = self.final_layer(x) + + return logits +``` + +Model initialization that be used for training and inference: +``` +transformer = Transformer( + num_layers=num_layers, + d_model=d_model, + num_heads=num_heads, + dff=dff, + input_vocab_size=tokenizers.pt.get_vocab_size().numpy(), + target_vocab_size=tokenizers.en.get_vocab_size().numpy(), + dropout_rate=dropout_rate +) +``` ### PyTorch + +### HuggingFace + ## Application The transformer has had great success in natural language processing (NLP). Many large language models such as GPT-2, GPT-3, GPT-4, Claude, BERT, XLNet, RoBERTa and ChatGPT demonstrate the ability of transformers to perform a wide variety of such NLP-related tasks, and have the potential to find real-world applications. From f56131349d1ad0e6e27209ea3d9217c13e695e8e Mon Sep 17 00:00:00 2001 From: SAM <60264918+SAM-DEV007@users.noreply.github.com> Date: Fri, 31 May 2024 17:13:19 +0530 Subject: [PATCH 05/47] Update Transformers.md Added python tag to code blocks --- contrib/machine-learning/Transformers.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/machine-learning/Transformers.md b/contrib/machine-learning/Transformers.md index a5a56ec..ffdea05 100644 --- a/contrib/machine-learning/Transformers.md +++ b/contrib/machine-learning/Transformers.md @@ -64,13 +64,13 @@ Tensorflow provides the transformer encoder and decoder block that can be implem More information on [encoder](https://www.tensorflow.org/api_docs/python/tfm/nlp/layers/TransformerEncoderBlock) and [decoder](https://www.tensorflow.org/api_docs/python/tfm/nlp/layers/TransformerDecoderBlock) block mentioned in the code. Imports: -``` +```python import tensorflow as tf import tensorflow_models as tfm ``` Adding word embeddings and positional encoding: -``` +```python class PositionalEmbedding(tf.keras.layers.Layer): def __init__(self, vocab_size, d_model): super().__init__() @@ -89,7 +89,7 @@ class PositionalEmbedding(tf.keras.layers.Layer): ``` Creating the encoder for the transformer: -``` +```python class Encoder(tf.keras.layers.Layer): def __init__(self, num_layers, d_model, num_heads, dff, vocab_size, dropout_rate=0.1): @@ -121,7 +121,7 @@ class Encoder(tf.keras.layers.Layer): ``` Creating the decoder for the transformer: -``` +```python class Decoder(tf.keras.layers.Layer): def __init__(self, num_layers, d_model, num_heads, dff, vocab_size, dropout_rate=0.1): @@ -151,7 +151,7 @@ class Decoder(tf.keras.layers.Layer): ``` Combining the encoder and decoder to create the transformer: -``` +```python class Transformer(tf.keras.Model): def __init__(self, num_layers, d_model, num_heads, dff, input_vocab_size, target_vocab_size, dropout_rate=0.1): @@ -179,7 +179,7 @@ class Transformer(tf.keras.Model): ``` Model initialization that be used for training and inference: -``` +```python transformer = Transformer( num_layers=num_layers, d_model=d_model, From ca9c6a9a1f23d1e6b5901954c8a5c5c772bd80a7 Mon Sep 17 00:00:00 2001 From: SAM <60264918+SAM-DEV007@users.noreply.github.com> Date: Fri, 31 May 2024 17:44:28 +0530 Subject: [PATCH 06/47] Update Transformers.md Added PyTorch implementation --- contrib/machine-learning/Transformers.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/contrib/machine-learning/Transformers.md b/contrib/machine-learning/Transformers.md index ffdea05..cb90cf1 100644 --- a/contrib/machine-learning/Transformers.md +++ b/contrib/machine-learning/Transformers.md @@ -56,7 +56,9 @@ The sine and cosine functions of different frequencies: ### Theory Text is converted to numerical representations called tokens, and each token is converted into a vector via looking up from a word embedding table. At each layer, each token is then contextualized within the scope of the context window with other tokens via a parallel multi-head attention mechanism -allowing the signal for key tokens to be amplified and less important tokens to be diminished. +allowing the signal for key tokens to be amplified and less important tokens to be diminished. + +The transformer uses an encoder-decoder architecture. The encoder extracts features from an input sentence, and the decoder uses the features to produce an output sentence. Some architectures use full encoders and decoders, autoregressive encoders and decoders, or combination of both. This depends on the usage and context of the input. ### Tensorflow Tensorflow provides the transformer encoder and decoder block that can be implemented by the specification of the user. Although, the transformer is not provided as a standalone to be imported and executed, the user has to create the model first. They also have a tutorial on how to implement the transformer from scratch for machine translation and can be found [here](https://www.tensorflow.org/text/tutorials/transformer). @@ -192,10 +194,30 @@ transformer = Transformer( ``` ### PyTorch +Unlike Tensorflow, PyTorch provides the full implementation of the transformer model that can be executed on the go. More information can be found [here](https://pytorch.org/docs/stable/_modules/torch/nn/modules/transformer.html#Transformer). A full implementation of the model can be found [here](https://github.com/pytorch/examples/tree/master/word_language_model). +Imports: +```python +import torch +import torch.nn as nn +``` + +Initializing the model: +```python +transformer = nn.Transformer(nhead=16, num_encoder_layers=8) +``` + +Sample Implementation: +```python +src = torch.rand((10, 32, 512)) +tgt = torch.rand((20, 32, 512)) + +output = transformer(src, tgt) +``` ### HuggingFace + ## Application The transformer has had great success in natural language processing (NLP). Many large language models such as GPT-2, GPT-3, GPT-4, Claude, BERT, XLNet, RoBERTa and ChatGPT demonstrate the ability of transformers to perform a wide variety of such NLP-related tasks, and have the potential to find real-world applications. From d81e875a3235d7c9f50f9a42bb359bf80d3146a1 Mon Sep 17 00:00:00 2001 From: SAM <60264918+SAM-DEV007@users.noreply.github.com> Date: Fri, 31 May 2024 18:32:47 +0530 Subject: [PATCH 07/47] Update Transformers.md Added outputs for PyTorch and HuggingFace implementation --- contrib/machine-learning/Transformers.md | 114 ++++++++++++++++++++++- 1 file changed, 112 insertions(+), 2 deletions(-) diff --git a/contrib/machine-learning/Transformers.md b/contrib/machine-learning/Transformers.md index cb90cf1..e9e50e8 100644 --- a/contrib/machine-learning/Transformers.md +++ b/contrib/machine-learning/Transformers.md @@ -61,6 +61,8 @@ allowing the signal for key tokens to be amplified and less important tokens to The transformer uses an encoder-decoder architecture. The encoder extracts features from an input sentence, and the decoder uses the features to produce an output sentence. Some architectures use full encoders and decoders, autoregressive encoders and decoders, or combination of both. This depends on the usage and context of the input. ### Tensorflow +TensorFlow is a free and open-source software library for machine learning and artificial intelligence. It can be used across a range of tasks but has a particular focus on training and inference of deep neural networks. It was developed by the Google Brain team for Google's internal use in research and production. + Tensorflow provides the transformer encoder and decoder block that can be implemented by the specification of the user. Although, the transformer is not provided as a standalone to be imported and executed, the user has to create the model first. They also have a tutorial on how to implement the transformer from scratch for machine translation and can be found [here](https://www.tensorflow.org/text/tutorials/transformer). More information on [encoder](https://www.tensorflow.org/api_docs/python/tfm/nlp/layers/TransformerEncoderBlock) and [decoder](https://www.tensorflow.org/api_docs/python/tfm/nlp/layers/TransformerDecoderBlock) block mentioned in the code. @@ -193,7 +195,22 @@ transformer = Transformer( ) ``` +Sample: +```python +src = tf.random.uniform((64, 40)) +tgt = tf.random.uniform((64, 50)) + +output = transformer((src, tgt)) +``` + +O/P: +``` + +``` + ### PyTorch +PyTorch is a machine learning library based on the Torch library, used for applications such as computer vision and natural language processing, originally developed by Meta AI and now part of the Linux Foundation umbrella. + Unlike Tensorflow, PyTorch provides the full implementation of the transformer model that can be executed on the go. More information can be found [here](https://pytorch.org/docs/stable/_modules/torch/nn/modules/transformer.html#Transformer). A full implementation of the model can be found [here](https://github.com/pytorch/examples/tree/master/word_language_model). Imports: @@ -207,7 +224,7 @@ Initializing the model: transformer = nn.Transformer(nhead=16, num_encoder_layers=8) ``` -Sample Implementation: +Sample: ```python src = torch.rand((10, 32, 512)) tgt = torch.rand((20, 32, 512)) @@ -215,8 +232,101 @@ tgt = torch.rand((20, 32, 512)) output = transformer(src, tgt) ``` -### HuggingFace +O/P: +``` +tensor([[[ 0.2938, -0.4824, -0.7816, ..., 0.0742, 0.5162, 0.3632], + [-0.0786, -0.5241, 0.6384, ..., 0.3462, -0.0618, 0.9943], + [ 0.7827, 0.1067, -0.1637, ..., -1.7730, -0.3322, -0.0029], + ..., + [-0.3202, 0.2341, -0.0896, ..., -0.9714, -0.1251, -0.0711], + [-0.1663, -0.5047, -0.0404, ..., -0.9339, 0.3963, 0.1018], + [ 1.2834, -0.4400, 0.0486, ..., -0.6876, -0.4752, 0.0180]], + [[ 0.9869, -0.7384, -1.0704, ..., -0.9417, 1.3279, -0.1665], + [ 0.3445, -0.2454, -0.3644, ..., -0.4856, -1.1004, -0.6819], + [ 0.7568, -0.3151, -0.5034, ..., -1.2081, -0.7119, 0.3775], + ..., + [-0.0451, -0.7596, 0.0168, ..., -0.8267, -0.3272, 1.0457], + [ 0.3150, -0.6588, -0.1840, ..., 0.1822, -0.0653, 0.9053], + [ 0.8692, -0.3519, 0.3128, ..., -1.8446, -0.2325, -0.8662]], + + [[ 0.9719, -0.3113, 0.4637, ..., -0.4422, 1.2348, 0.8274], + [ 0.3876, -0.9529, -0.7810, ..., -0.5843, -1.1439, -0.3366], + [-0.5774, 0.3789, -0.2819, ..., -1.4057, 0.4352, 0.1474], + ..., + [ 0.6899, -0.1146, -0.3297, ..., -1.7059, -0.1750, 0.4203], + [ 0.3689, -0.5174, -0.1253, ..., 0.1417, 0.4159, 0.7560], + [ 0.5024, -0.7996, 0.1592, ..., -0.8344, -1.1125, 0.4736]], + + ..., + + [[ 0.0704, -0.3971, -0.2768, ..., -1.9929, 0.8608, 1.2264], + [ 0.4013, -0.0962, -0.0965, ..., -0.4452, -0.8682, -0.4593], + [ 0.1656, 0.5224, -0.1723, ..., -1.5785, 0.3219, 1.1507], + ..., + [-0.9443, 0.4653, 0.2936, ..., -0.9840, -0.0142, -0.1595], + [-0.6544, -0.3294, -0.0803, ..., 0.1623, -0.5061, 0.9824], + [-0.0978, -1.0023, -0.6915, ..., -0.2296, -0.0594, -0.4715]], + + [[ 0.6531, -0.9285, -0.0331, ..., -1.1481, 0.7768, -0.7321], + [ 0.3325, -0.6683, -0.6083, ..., -0.4501, 0.2289, 0.3573], + [-0.6750, 0.4600, -0.8512, ..., -2.0097, -0.5159, 0.2773], + ..., + [-1.4356, -1.0135, 0.0081, ..., -1.2985, -0.3715, -0.2678], + [ 0.0546, -0.2111, -0.0965, ..., -0.3822, -0.4612, 1.6217], + [ 0.7700, -0.5309, -0.1754, ..., -2.2807, -0.0320, -1.5551]], + + [[ 0.2399, -0.9659, 0.1086, ..., -1.1756, 0.4063, 0.0615], + [-0.2202, -0.7972, -0.5024, ..., -0.9126, -1.5248, 0.2418], + [ 0.5215, 0.4540, 0.0036, ..., -0.2135, 0.2145, 0.6638], + ..., + [-0.2190, -0.4967, 0.7149, ..., -0.3324, 0.3502, 1.0624], + [-0.0108, -0.9205, -0.1315, ..., -1.0153, 0.2989, 1.1415], + [ 1.1284, -0.6560, 0.6755, ..., -1.2157, 0.8580, -0.5022]]], + grad_fn=) +``` +``` +>> output.shape +torch.Size([20, 32, 512]) +``` + +### HuggingFace +Hugging Face, Inc. is a French-American company incorporated under the Delaware General Corporation Law and based in New York City that develops computation tools for building applications using machine learning. + +It has a wide-range of models that can implemented in Tensorflow, PyTorch and other development backends as well. The models are already trained on a dataset and can be pretrained on custom dataset for customized use, according to the user. The information for training the model and loading the pretrained model can be found [here](https://huggingface.co/docs/transformers/en/training). + +In HuggingFace, `pipeline` is used to run inference from the trained model available in the Hub. This is very beginner friendly. The model is downloaded to the local system on running the script before running the inference. It has to be made sure that the model downloaded does not exceed your available data plan. + +Imports: +```python +from transformers import pipeline +``` + +Initialization: + +The model used here is BART (large) which was trained on MultiNLI dataset, which consist of sentence paired with its textual entailment. +```python +classifier = pipeline(model="facebook/bart-large-mnli") +``` + +Sample: + +The first argument is the sentence which needs to be analyzed. The second argument, `candidate_labels`, is the list of labels which most likely the first argument sentence belongs to. The output dictionary will have a key as `score`, where the highest index is the textual entailment of the sentence with the index of the label in the list. + +```python +output = classifier( + "I need to leave but later", + candidate_labels=["urgent", "not urgent", "sleep"], +) +``` + +O/P: + +``` +{'sequence': 'I need to leave but later', + 'labels': ['not urgent', 'urgent', 'sleep'], + 'scores': [0.8889380097389221, 0.10631518065929413, 0.00474683940410614]} +``` ## Application The transformer has had great success in natural language processing (NLP). Many large language models such as GPT-2, GPT-3, GPT-4, Claude, BERT, XLNet, RoBERTa and ChatGPT demonstrate the ability of transformers to perform a wide variety of such NLP-related tasks, and have the potential to find real-world applications. From 251c4d86894b26e113b1b4426aeaf412c0b4c977 Mon Sep 17 00:00:00 2001 From: SAM <60264918+SAM-DEV007@users.noreply.github.com> Date: Fri, 31 May 2024 18:43:19 +0530 Subject: [PATCH 08/47] Update Transformers.md Added Tensorflow output and fixed wrong mentions --- contrib/machine-learning/Transformers.md | 93 +++++++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) diff --git a/contrib/machine-learning/Transformers.md b/contrib/machine-learning/Transformers.md index e9e50e8..d30bd63 100644 --- a/contrib/machine-learning/Transformers.md +++ b/contrib/machine-learning/Transformers.md @@ -189,8 +189,8 @@ transformer = Transformer( d_model=d_model, num_heads=num_heads, dff=dff, - input_vocab_size=tokenizers.pt.get_vocab_size().numpy(), - target_vocab_size=tokenizers.en.get_vocab_size().numpy(), + input_vocab_size=64, + target_vocab_size=64, dropout_rate=dropout_rate ) ``` @@ -205,7 +205,96 @@ output = transformer((src, tgt)) O/P: ``` + +``` +``` +>>> output.shape +TensorShape([64, 50, 64]) ``` ### PyTorch From 44303ff8e04e496e0f545d92a60e9758b971e314 Mon Sep 17 00:00:00 2001 From: SAM <60264918+SAM-DEV007@users.noreply.github.com> Date: Fri, 31 May 2024 18:45:07 +0530 Subject: [PATCH 09/47] Update Transformers.md Extended Introduction --- contrib/machine-learning/Transformers.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contrib/machine-learning/Transformers.md b/contrib/machine-learning/Transformers.md index d30bd63..97346bd 100644 --- a/contrib/machine-learning/Transformers.md +++ b/contrib/machine-learning/Transformers.md @@ -1,8 +1,9 @@ # Transformers ## Introduction A transformer is a deep learning architecture developed by Google and based on the multi-head attention mechanism. It is based on the softmax-based attention -mechanism. Before transformers, predecessors of attention mechanism were added to gated recurrent neural networks, such as LSTMs and gated recurrent units (GRUs), which -processed datasets sequentially. Dependency on previous token computations prevented them from being able to parallelize the attention mechanism. +mechanism. Before transformers, predecessors of attention mechanism were added to gated recurrent neural networks, such as LSTMs and gated recurrent units (GRUs), which processed datasets sequentially. Dependency on previous token computations prevented them from being able to parallelize the attention mechanism. + +Transformers are a revolutionary approach to natural language processing (NLP). Unlike older models, they excel at understanding long-range connections between words. This "attention" mechanism lets them grasp the context of a sentence, making them powerful for tasks like machine translation, text summarization, and question answering. Introduced in 2017, transformers are now the backbone of many large language models, including tools you might use every day. Their ability to handle complex relationships in language is fueling advancements in AI across various fields. ## Model Architecture

Model Architecture

From f65c949564f003591c746088bf8c25be44a65853 Mon Sep 17 00:00:00 2001 From: Ritesh Date: Sun, 2 Jun 2024 09:17:22 +0530 Subject: [PATCH 10/47] Create hierarchical-clustering.md --- .../hierarchical-clustering.md | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 contrib/machine-learning/hierarchical-clustering.md diff --git a/contrib/machine-learning/hierarchical-clustering.md b/contrib/machine-learning/hierarchical-clustering.md new file mode 100644 index 0000000..3f9e606 --- /dev/null +++ b/contrib/machine-learning/hierarchical-clustering.md @@ -0,0 +1,119 @@ +# Hierarchical Clustering + +Hierarchical Clustering is a method of cluster analysis that seeks to build a hierarchy of clusters. This README provides an overview of the hierarchical clustering algorithm, including its fundamental concepts, types, steps, and how to implement it using Python. + +## Table of Contents + +1. [Introduction](#introduction) +2. [Concepts](#concepts) +3. [Types of Hierarchical Clustering](#types-of-hierarchical-clustering) +4. [Steps in Hierarchical Clustering](#steps-in-hierarchical-clustering) +5. [Linkage Criteria](#linkage-criteria) +6. [Implementation](#implementation) + - [Using Scikit-learn](#using-scikit-learn) + - [Code Example](#code-example) +7. [Evaluation Metrics](#evaluation-metrics) +8. [Conclusion](#conclusion) +9. [References](#references) + +## Introduction + +Hierarchical Clustering is an unsupervised learning method used to group similar objects into clusters. Unlike other clustering techniques, hierarchical clustering does not require the number of clusters to be specified beforehand. It produces a tree-like structure called a dendrogram, which displays the arrangement of the clusters and their sub-clusters. + +## Concepts + +### Dendrogram + +A dendrogram is a tree-like diagram that records the sequences of merges or splits. It is a useful tool for visualizing the process of hierarchical clustering. + +### Distance Measure + +Distance measures are used to quantify the similarity or dissimilarity between data points. Common distance measures include Euclidean distance, Manhattan distance, and cosine similarity. + +### Linkage Criteria + +Linkage criteria determine how the distance between clusters is calculated. Different linkage criteria include single linkage, complete linkage, average linkage, and Ward's linkage. + +## Types of Hierarchical Clustering + +1. **Agglomerative Clustering (Bottom-Up Approach)**: + - Starts with each data point as a separate cluster. + - Repeatedly merges the closest pairs of clusters until only one cluster remains or a stopping criterion is met. + +2. **Divisive Clustering (Top-Down Approach)**: + - Starts with all data points in a single cluster. + - Repeatedly splits clusters into smaller clusters until each data point is its own cluster or a stopping criterion is met. + +## Steps in Hierarchical Clustering + +1. **Calculate Distance Matrix**: Compute the distance between each pair of data points. +2. **Create Clusters**: Treat each data point as a single cluster. +3. **Merge Closest Clusters**: Find the two clusters that are closest to each other and merge them into a single cluster. +4. **Update Distance Matrix**: Update the distance matrix to reflect the distance between the new cluster and the remaining clusters. +5. **Repeat**: Repeat steps 3 and 4 until all data points are merged into a single cluster or the desired number of clusters is achieved. + +## Linkage Criteria + +1. **Single Linkage (Minimum Linkage)**: The distance between two clusters is defined as the minimum distance between any single data point in the first cluster and any single data point in the second cluster. +2. **Complete Linkage (Maximum Linkage)**: The distance between two clusters is defined as the maximum distance between any single data point in the first cluster and any single data point in the second cluster. +3. **Average Linkage**: The distance between two clusters is defined as the average distance between all pairs of data points, one from each cluster. +4. **Ward's Linkage**: The distance between two clusters is defined as the increase in the sum of squared deviations from the mean when the two clusters are merged. + +## Implementation + +### Using Scikit-learn + +Scikit-learn is a popular machine learning library in Python that provides tools for hierarchical clustering. + +### Code Example + +```python +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +from scipy.cluster.hierarchy import dendrogram, linkage +from sklearn.cluster import AgglomerativeClustering +from sklearn.preprocessing import StandardScaler + +# Load dataset +data = pd.read_csv('path/to/your/dataset.csv') + +# Preprocess the data +scaler = StandardScaler() +data_scaled = scaler.fit_transform(data) + +# Perform hierarchical clustering +Z = linkage(data_scaled, method='ward') + +# Plot the dendrogram +plt.figure(figsize=(10, 7)) +dendrogram(Z) +plt.title('Dendrogram') +plt.xlabel('Data Points') +plt.ylabel('Distance') +plt.show() + +# Perform Agglomerative Clustering +agg_clustering = AgglomerativeClustering(n_clusters=3, affinity='euclidean', linkage='ward') +labels = agg_clustering.fit_predict(data_scaled) + +# Add cluster labels to the original data +data['Cluster'] = labels +print(data.head()) +``` + +## Evaluation Metrics + +- **Silhouette Score**: Measures how similar a data point is to its own cluster compared to other clusters. +- **Cophenetic Correlation Coefficient**: Measures how faithfully a dendrogram preserves the pairwise distances between the original data points. +- **Dunn Index**: Ratio of the minimum inter-cluster distance to the maximum intra-cluster distance. + +## Conclusion + +Hierarchical clustering is a versatile and intuitive method for clustering data. It is particularly useful when the number of clusters is not known beforehand. By understanding the different linkage criteria and evaluation metrics, one can effectively apply hierarchical clustering to various types of data. + +## References + +- [Scikit-learn Documentation](https://scikit-learn.org/stable/modules/clustering.html#hierarchical-clustering) +- [Wikipedia: Hierarchical Clustering](https://en.wikipedia.org/wiki/Hierarchical_clustering) +- [Towards Data Science: Hierarchical Clustering Explained](https://towardsdatascience.com/hierarchical-clustering-explained-925d9e1600c1) From 5b6cd66f79e2cc0341f94bd0ec3ee935ccf8a20c Mon Sep 17 00:00:00 2001 From: Ritesh Date: Sun, 2 Jun 2024 09:21:45 +0530 Subject: [PATCH 11/47] Update index.md --- contrib/machine-learning/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/machine-learning/index.md b/contrib/machine-learning/index.md index b6945cd..20305dc 100644 --- a/contrib/machine-learning/index.md +++ b/contrib/machine-learning/index.md @@ -15,4 +15,5 @@ - [Logistic Regression](logistic-regression.md) - [Types_of_Cost_Functions](cost-functions.md) - [Clustering](clustering.md) +- [Hierarchical Clustering](hierarchical-clustering.md) - [Grid Search](grid-search.md) From 8ef6a2febc2ec303ffdc0702d838e2caa1462b17 Mon Sep 17 00:00:00 2001 From: Soubeer Koley Date: Sun, 2 Jun 2024 09:27:46 +0530 Subject: [PATCH 12/47] added ensemble learning --- contrib/machine-learning/ensemble_learning.md | 140 ++++++++++++++++++ contrib/machine-learning/index.md | 3 +- 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 contrib/machine-learning/ensemble_learning.md diff --git a/contrib/machine-learning/ensemble_learning.md b/contrib/machine-learning/ensemble_learning.md new file mode 100644 index 0000000..940bd09 --- /dev/null +++ b/contrib/machine-learning/ensemble_learning.md @@ -0,0 +1,140 @@ +# Ensemble Learning + +Ensemble Learning is a powerful machine learning paradigm that combines multiple models to achieve better performance than any individual model. The idea is to leverage the strengths of different models to improve overall accuracy, robustness, and generalization. + + + +## Introduction + +Ensemble Learning is a technique that combines the predictions from multiple machine learning models to make more accurate and robust predictions than a single model. It leverages the diversity of different models to reduce errors and improve performance. + +## Types of Ensemble Learning + +### Bagging + +Bagging, or Bootstrap Aggregating, involves training multiple versions of the same model on different subsets of the training data and averaging their predictions. The most common example of bagging is the `RandomForest` algorithm. + +### Boosting + +Boosting focuses on training models sequentially, where each new model corrects the errors made by the previous ones. This way, the ensemble learns from its mistakes, leading to improved performance. `AdaBoost` and `Gradient Boosting` are popular examples of boosting algorithms. + +### Stacking + +Stacking involves training multiple models (the base learners) and a meta-model that combines their predictions. The base learners are trained on the original dataset, while the meta-model is trained on the outputs of the base learners. This approach allows leveraging the strengths of different models. + +## Advantages and Disadvantages + +### Advantages + +- **Improved Accuracy**: Combines the strengths of multiple models. +- **Robustness**: Reduces the risk of overfitting and model bias. +- **Versatility**: Can be applied to various machine learning tasks, including classification and regression. + +### Disadvantages + +- **Complexity**: More complex than individual models, making interpretation harder. +- **Computational Cost**: Requires more computational resources and training time. +- **Implementation**: Can be challenging to implement and tune effectively. + +## Key Concepts + +- **Diversity**: The models in the ensemble should be diverse to benefit from their different strengths. +- **Voting/Averaging**: For classification, majority voting is used to combine predictions. For regression, averaging is used. +- **Weighting**: In some ensembles, models are weighted based on their accuracy or other metrics. + +## Code Examples + +### Bagging with Random Forest + +Below is an example of using Random Forest for classification on the Iris dataset. + +```python +import numpy as np +import pandas as pd +from sklearn.datasets import load_iris +from sklearn.ensemble import RandomForestClassifier +from sklearn.model_selection import train_test_split +from sklearn.metrics import accuracy_score, classification_report + +# Load dataset +iris = load_iris() +X, y = iris.data, iris.target + +# Split dataset +X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) + +# Initialize Random Forest model +clf = RandomForestClassifier(n_estimators=100, random_state=42) + +# Train the model +clf.fit(X_train, y_train) + +# Make predictions +y_pred = clf.predict(X_test) + +# Evaluate the model +accuracy = accuracy_score(y_test, y_pred) +print(f"Accuracy: {accuracy * 100:.2f}%") +print("Classification Report:\n", classification_report(y_test, y_pred)) +``` + +### Boosting with AdaBoost +Below is an example of using AdaBoost for classification on the Iris dataset. + +``` +from sklearn.ensemble import AdaBoostClassifier +from sklearn.tree import DecisionTreeClassifier + +# Initialize base model +base_model = DecisionTreeClassifier(max_depth=1) + +# Initialize AdaBoost model +ada_clf = AdaBoostClassifier(base_estimator=base_model, n_estimators=50, random_state=42) + +# Train the model +ada_clf.fit(X_train, y_train) + +# Make predictions +y_pred = ada_clf.predict(X_test) + +# Evaluate the model +accuracy = accuracy_score(y_test, y_pred) +print(f"Accuracy: {accuracy * 100:.2f}%") +print("Classification Report:\n", classification_report(y_test, y_pred)) +``` + +### Stacking with Multiple Models +Below is an example of using stacking with multiple models for classification on the Iris dataset. + +``` +from sklearn.linear_model import LogisticRegression +from sklearn.neighbors import KNeighborsClassifier +from sklearn.svm import SVC +from sklearn.ensemble import StackingClassifier + +# Define base models +base_models = [ + ('knn', KNeighborsClassifier(n_neighbors=5)), + ('svc', SVC(kernel='linear', probability=True)) +] + +# Define meta-model +meta_model = LogisticRegression() + +# Initialize Stacking model +stacking_clf = StackingClassifier(estimators=base_models, final_estimator=meta_model, cv=5) + +# Train the model +stacking_clf.fit(X_train, y_train) + +# Make predictions +y_pred = stacking_clf.predict(X_test) + +# Evaluate the model +accuracy = accuracy_score(y_test, y_pred) +print(f"Accuracy: {accuracy * 100:.2f}%") +print("Classification Report:\n", classification_report(y_test, y_pred)) +``` + +## Conclusion +Ensemble Learning is a powerful technique that combines multiple models to improve overall performance. By leveraging the strengths of different models, it provides better accuracy, robustness, and generalization. However, it comes with increased complexity and computational cost. Understanding and implementing ensemble methods can significantly enhance machine learning solutions. \ No newline at end of file diff --git a/contrib/machine-learning/index.md b/contrib/machine-learning/index.md index 073bca9..a46cd7a 100644 --- a/contrib/machine-learning/index.md +++ b/contrib/machine-learning/index.md @@ -9,4 +9,5 @@ - [TensorFlow.md](tensorFlow.md) - [PyTorch.md](pytorch.md) - [Types of optimizers](Types_of_optimizers.md) -- [Random Forest](Random_Forest.md) \ No newline at end of file +- [Random Forest](Random_Forest.md) +- [Ensemble Learning](ensemble_learning.md) \ No newline at end of file From 402289d3ceae6add26458f41d33364eff322f8e2 Mon Sep 17 00:00:00 2001 From: SAM <60264918+SAM-DEV007@users.noreply.github.com> Date: Sun, 2 Jun 2024 10:23:09 +0530 Subject: [PATCH 13/47] Rename Transformers.md to transformers.md --- contrib/machine-learning/{Transformers.md => transformers.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename contrib/machine-learning/{Transformers.md => transformers.md} (100%) diff --git a/contrib/machine-learning/Transformers.md b/contrib/machine-learning/transformers.md similarity index 100% rename from contrib/machine-learning/Transformers.md rename to contrib/machine-learning/transformers.md From e13fb234f2829a1b918aac3c044e4feef5066d34 Mon Sep 17 00:00:00 2001 From: SAM <60264918+SAM-DEV007@users.noreply.github.com> Date: Sun, 2 Jun 2024 10:23:56 +0530 Subject: [PATCH 14/47] Add transformers.md --- contrib/machine-learning/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/machine-learning/index.md b/contrib/machine-learning/index.md index b6945cd..13d9440 100644 --- a/contrib/machine-learning/index.md +++ b/contrib/machine-learning/index.md @@ -16,3 +16,4 @@ - [Types_of_Cost_Functions](cost-functions.md) - [Clustering](clustering.md) - [Grid Search](grid-search.md) +- [Transformers](transformers.md) From 229458043245de432c96f05457dd79330d568a92 Mon Sep 17 00:00:00 2001 From: SAM <60264918+SAM-DEV007@users.noreply.github.com> Date: Sun, 2 Jun 2024 10:39:37 +0530 Subject: [PATCH 15/47] Update transformers.md Added source for the image --- contrib/machine-learning/transformers.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contrib/machine-learning/transformers.md b/contrib/machine-learning/transformers.md index 97346bd..9fbfa6d 100644 --- a/contrib/machine-learning/transformers.md +++ b/contrib/machine-learning/transformers.md @@ -6,7 +6,10 @@ mechanism. Before transformers, predecessors of attention mechanism were added t Transformers are a revolutionary approach to natural language processing (NLP). Unlike older models, they excel at understanding long-range connections between words. This "attention" mechanism lets them grasp the context of a sentence, making them powerful for tasks like machine translation, text summarization, and question answering. Introduced in 2017, transformers are now the backbone of many large language models, including tools you might use every day. Their ability to handle complex relationships in language is fueling advancements in AI across various fields. ## Model Architecture -

Model Architecture

+

+ Model Architecture
+Source: Attention Is All You Need - Figure 1 +

### Encoder The encoder is composed of a stack of identical layers. Each layer has two sub-layers. The first is a multi-head self-attention mechanism, and the second is a simple, positionwise fully connected feed-forward network. Each encoder consists of two major components: a self-attention mechanism and a feed-forward neural network. The self-attention mechanism accepts input encodings from the previous encoder and weights their relevance to each other to generate output encodings. The feed-forward neural network further processes each output encoding individually. These output encodings are then passed to the next encoder as its input, as well as to the decoders. From 07a1e737606d10d7e96e2291cec21003309bfbf0 Mon Sep 17 00:00:00 2001 From: SAM <60264918+SAM-DEV007@users.noreply.github.com> Date: Sun, 2 Jun 2024 10:46:21 +0530 Subject: [PATCH 16/47] Update transformers.md Added bibliography --- contrib/machine-learning/transformers.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/contrib/machine-learning/transformers.md b/contrib/machine-learning/transformers.md index 9fbfa6d..0799b7f 100644 --- a/contrib/machine-learning/transformers.md +++ b/contrib/machine-learning/transformers.md @@ -430,4 +430,11 @@ These may include: - Text generation - Biological sequence analysis - Computer code generation -- Video analysis + +## Bibliography +- [Attention Is All You Need](https://arxiv.org/pdf/1706.03762) +- [Tensorflow Tutorial](https://www.tensorflow.org/text/tutorials/transformer) +- [Tensorflow Models Docs](https://www.tensorflow.org/api_docs/python/tfm/nlp/layers) +- [Wikipedia](https://en.wikipedia.org/wiki/Transformer_(deep_learning_architecture)) +- [HuggingFace](https://huggingface.co/docs/transformers/en/index) +- [PyTorch](https://pytorch.org/docs/stable/generated/torch.nn.Transformer.html) From 3e35783d59919de603e6d11e81df54fdf47662b2 Mon Sep 17 00:00:00 2001 From: SAM <8dmasters@gmail.com> Date: Sun, 2 Jun 2024 16:19:11 +0530 Subject: [PATCH 17/47] Create transformer-architecture.png --- .../assets/transformer-architecture.png | Bin 0 -> 57018 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 contrib/machine-learning/assets/transformer-architecture.png diff --git a/contrib/machine-learning/assets/transformer-architecture.png b/contrib/machine-learning/assets/transformer-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..2854ab0a8d3e6f0ba0c53735afb57e81eb825a3f GIT binary patch literal 57018 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 Date: Sun, 2 Jun 2024 16:22:50 +0530 Subject: [PATCH 18/47] Update transformers.md Added image location --- contrib/machine-learning/transformers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/machine-learning/transformers.md b/contrib/machine-learning/transformers.md index 0799b7f..0dcf697 100644 --- a/contrib/machine-learning/transformers.md +++ b/contrib/machine-learning/transformers.md @@ -7,7 +7,7 @@ Transformers are a revolutionary approach to natural language processing (NLP). ## Model Architecture

- Model Architecture
+ Model Architecture
Source:
Attention Is All You Need - Figure 1

From 843eb9b01959f199b6bba37ac3839356c3023f6d Mon Sep 17 00:00:00 2001 From: anamika123 Date: Sun, 2 Jun 2024 22:04:58 +0530 Subject: [PATCH 19/47] eval function --- contrib/advanced-python/eval_function.md | 75 ++++++++++++++++++++++++ contrib/advanced-python/index.md | 1 + 2 files changed, 76 insertions(+) create mode 100644 contrib/advanced-python/eval_function.md diff --git a/contrib/advanced-python/eval_function.md b/contrib/advanced-python/eval_function.md new file mode 100644 index 0000000..9e3ec54 --- /dev/null +++ b/contrib/advanced-python/eval_function.md @@ -0,0 +1,75 @@ +# Understanding the `eval` Function in Python +## Introduction + +The `eval` function in Python allows you to execute a string-based Python expression dynamically. This can be useful in various scenarios where you need to evaluate expressions that are not known until runtime. + +## Syntax +```python +eval(expression, globals=None, locals=None) +``` + +### Parameters: + +* expression: String is parsed and evaluated as a Python expression +* globals [optional]: Dictionary to specify the available global methods and variables. +* locals [optional]: Another dictionary to specify the available local methods and variables. + +## Examples +Example 1: +```python +result = eval('2 + 3 * 4') +print(result) # Output: 14 +``` +Example 2: + +```python +x = 10 +expression = 'x * 2' +result = eval(expression, {'x': x}) +print(result) # Output: 20 +``` +Example 3: +```python +x = 10 +def multiply(a, b): + return a * b +expression = 'multiply(x, 5) + 2' +result = eval(expression) +print("Result:",result) # Output: Result:52 +``` +Example 4: +```python +expression = input("Enter a Python expression: ") +result = eval(expression) +print("Result:", result) +#input= "3+2" +#Output: Result:5 +``` + +Example 5: +```python +import numpy as np +a=np.random.randint(1,9) +b=np.random.randint(1,9) +operations=["*","-","+"] +op=np.random.choice(operations) + +expression=str(a)+op+str(b) +correct_answer=eval(expression) +given_answer=int(input(str(a)+" "+op+" "+str(b)+" = ")) + +if given_answer==correct_answer: + print("Correct") +else: + print("Incorrect") + print("correct answer is :" ,correct_answer) + +#2 * 1 = 8 +#Incorrect +#correct answer is : 2 +#or +#3 * 2 = 6 +#Correct +``` +## Conclusion +The eval function is a powerful tool in Python that allows for dynamic evaluation of expressions. \ No newline at end of file diff --git a/contrib/advanced-python/index.md b/contrib/advanced-python/index.md index b31544e..9419480 100644 --- a/contrib/advanced-python/index.md +++ b/contrib/advanced-python/index.md @@ -10,3 +10,4 @@ - [Protocols](protocols.md) - [Exception Handling in Python](exception-handling.md) - [Generators](generators.md) +- [Eval Function](eval_function.md) From ea37cbb25457eaf0c650cd6822ff62fdb63da3a9 Mon Sep 17 00:00:00 2001 From: Lingamuneni Santhosh Siddhardha <103999924+Santhosh-Siddhardha@users.noreply.github.com> Date: Sun, 2 Jun 2024 22:07:01 +0530 Subject: [PATCH 20/47] Create list_comprehension.md Added Introduction Added Syntax Added Examples Added Conclusion --- contrib/advanced-python/list_comprehension.md | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 contrib/advanced-python/list_comprehension.md diff --git a/contrib/advanced-python/list_comprehension.md b/contrib/advanced-python/list_comprehension.md new file mode 100644 index 0000000..d9ab589 --- /dev/null +++ b/contrib/advanced-python/list_comprehension.md @@ -0,0 +1,73 @@ +# List Comprehension + +Creating lists concisely and expressively is what list comprehension in Python does. You can generate lists from already existing iterables like lists, tuples or strings with a short form. +This boosts the readability of code and reduces necessity of using explicit looping constructs. + +## Syntax : + +### Basic syntax + +```python +new_list = [expression for item in iterable] +``` +- **new_list**: This is the name given to the list that will be created using the list comprehension. +- **expression**: This is the expression that defines how each element of the new list will be generated or transformed. +- **item**: This variable represents each individual element from the iterable. It takes on the value of each element in the iterable during each iteration. +- **iterable**: This is the sequence-like object over which the iteration will take place. It provides the elements that will be processed by the expression. + +This list comprehension syntax `[expression for item in iterable]` allows you to generate a new list by applying a specific expression to each element in an iterable. + +### Syntax including condition + +```python +new_list = [expression for item in iterable if condition] +``` +- **new_list**: This is the name given to the list that will be created using the list comprehension. +- **expression**: This is the expression that defines how each element of the new list will be generated or transformed. +- **item**: This variable represents each individual element from the iterable. It takes on the value of each element in the iterable during each iteration. +- **iterable**: This is the sequence-like object over which the iteration will take place. It provides the elements that will be processed by the expression. +- **if condition**: This is an optional part of the syntax. It allows for conditional filtering of elements from the iterable. Only items that satisfy the condition + will be included in the new list. + + +## Examples: + +1. Generating a list of squares of numbers from 1 to 5: + +```python +squares = [x ** 2 for x in range(1, 6)] +print(squares) +``` + +- **Output** : +```python +[1, 4, 9, 16, 25] +``` + +2. Filtering even numbers from a list: + +```python +nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +even = [x for x in nums if x % 2 == 0] +print(even) +``` + +- **Output** : +```python +[2, 4, 6, 8, 10] +``` + +3. Flattening a list of lists: +```python +matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] +flat = [x for sublist in matrix for x in sublist] +print(flat) +``` + +- **Output** : +```python +[1, 2, 3, 4, 5, 6, 7, 8, 9] +``` + +List comprehension is a powerful feature in Python for creating lists based on existing iterables with a concise syntax. +By mastering list comprehension, developers can write cleaner, more expressive code and leverage Python's functional programming capabilities effectively. From b1f8d147a2abd103e4029c4e366011c1831fe784 Mon Sep 17 00:00:00 2001 From: Lingamuneni Santhosh Siddhardha <103999924+Santhosh-Siddhardha@users.noreply.github.com> Date: Sun, 2 Jun 2024 22:08:52 +0530 Subject: [PATCH 21/47] Update index.md Added List Comprehension section --- contrib/advanced-python/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/advanced-python/index.md b/contrib/advanced-python/index.md index b31544e..7ae2ede 100644 --- a/contrib/advanced-python/index.md +++ b/contrib/advanced-python/index.md @@ -10,3 +10,4 @@ - [Protocols](protocols.md) - [Exception Handling in Python](exception-handling.md) - [Generators](generators.md) +- [List Comprehension](#list_comprehension.md) From 53efed98073fba08e3c2867676273f654882c9cb Mon Sep 17 00:00:00 2001 From: Lingamuneni Santhosh Siddhardha <103999924+Santhosh-Siddhardha@users.noreply.github.com> Date: Sun, 2 Jun 2024 22:11:33 +0530 Subject: [PATCH 22/47] Update index.md made a small change --- contrib/advanced-python/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/advanced-python/index.md b/contrib/advanced-python/index.md index 7ae2ede..631423a 100644 --- a/contrib/advanced-python/index.md +++ b/contrib/advanced-python/index.md @@ -10,4 +10,4 @@ - [Protocols](protocols.md) - [Exception Handling in Python](exception-handling.md) - [Generators](generators.md) -- [List Comprehension](#list_comprehension.md) +- [List Comprehension](list_comprehension.md) From 0f0d58ce2dc3b013c9e0a12561e7208ff58cf93a Mon Sep 17 00:00:00 2001 From: Dishika Vaishkiyar <152963337+Dishika18@users.noreply.github.com> Date: Tue, 4 Jun 2024 00:18:27 +0530 Subject: [PATCH 23/47] Added Content: Scatter Chart in Matplotlib --- .../images/img_colorbar.png | Bin 0 -> 2386 bytes .../images/scatter_color.png | Bin 0 -> 12534 bytes .../images/scatter_coloreachdot.png | Bin 0 -> 12330 bytes .../images/scatter_colormap1.png | Bin 0 -> 12824 bytes .../images/scatter_colormap2.png | Bin 0 -> 17457 bytes .../images/scatter_compare.png | Bin 0 -> 12762 bytes .../images/simple_scatter.png | Bin 0 -> 11079 bytes 7 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 contrib/plotting-visualization/images/img_colorbar.png create mode 100644 contrib/plotting-visualization/images/scatter_color.png create mode 100644 contrib/plotting-visualization/images/scatter_coloreachdot.png create mode 100644 contrib/plotting-visualization/images/scatter_colormap1.png create mode 100644 contrib/plotting-visualization/images/scatter_colormap2.png create mode 100644 contrib/plotting-visualization/images/scatter_compare.png create mode 100644 contrib/plotting-visualization/images/simple_scatter.png diff --git a/contrib/plotting-visualization/images/img_colorbar.png b/contrib/plotting-visualization/images/img_colorbar.png new file mode 100644 index 0000000000000000000000000000000000000000..acc1ec5bd84d52a0f8bb3a9a4fc88405ca6e8edd GIT binary patch literal 2386 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 literal 0 HcmV?d00001 diff --git a/contrib/plotting-visualization/images/scatter_colormap1.png b/contrib/plotting-visualization/images/scatter_colormap1.png new file mode 100644 index 0000000000000000000000000000000000000000..212b368023d9babfbd95dc3e92106512ecb0ef55 GIT binary patch literal 12824 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

wwW_X%#MffrR3xV; zC!2kKdia%)eG+W>(3eiF=z126w$X2bm6Q!THW7N;>gKOx2QBaBY8Za&3Ve{7=dSEh zo)OTq4KT`7Ah%Vs3ksd##!)FS455wXO3GT~veI3r?@{ivjm3^ru$gB;_v_YH(%SCr z-;Q*e?KzoaxiZ~}TIuMwNVbA*OJ&1(Td25mHtk-70|nftKIz%uR9aSgq4wL>rHLaoVN-r0vu{gsgPI_Dbx2~1+YKKZdr8D;`Ud2C9+RDngJ7ORBU>6Z z5;!h-kfQ%Xn|wFfC(<^L0=>s#9US3iw3Y*uhSM8vK_MZD1Vno~RGqTu=63rV@8x^% z?kuc(6c5}#a723&Bh)u91}U*(pskJ-$J9->*5)C3)l%t8gQll8pH=$gte?NjydTrs z=e610-=(b?ZL36cq9!{X3fD9tC{cq{8oxyc_Y`dHJAlRgk1n@C0h%#P?sN5*FK@qz zt!hm{;aoQ8-ZPvt3GY|B%zJlAL6d+!WZ7OmIzXi<9$gPqy&$u2kQCMASB`rU0<=RR zmsnXJ+TJOwkF9ER*Ev_koT&Nr&}N;rmw_jYCZC6gCmo7u8#M7=rJj3+5(=R-WkcKu w3V0YbYz{*O&;RD4p1)*f{_TZBqq{_``+NF|9zJLRaTvi|QIO8OtatxE0MK}v%m4rY literal 0 HcmV?d00001 diff --git a/contrib/plotting-visualization/images/simple_scatter.png b/contrib/plotting-visualization/images/simple_scatter.png new file mode 100644 index 0000000000000000000000000000000000000000..bfa5b408811a67c88c7a42c396be6a327a3a971e GIT binary patch literal 11079 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 Date: Tue, 4 Jun 2024 00:22:12 +0530 Subject: [PATCH 24/47] Create matplotlib-scatter-plot.md --- .../matplotlib-scatter-plot.md | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 contrib/plotting-visualization/matplotlib-scatter-plot.md diff --git a/contrib/plotting-visualization/matplotlib-scatter-plot.md b/contrib/plotting-visualization/matplotlib-scatter-plot.md new file mode 100644 index 0000000..a9fa500 --- /dev/null +++ b/contrib/plotting-visualization/matplotlib-scatter-plot.md @@ -0,0 +1,155 @@ +# Scatter() plot in matplotlib +* A scatter plot is a type of data visualization that uses dots to show values for two variables, with one variable on the x-axis and the other on the y-axis. It's useful for identifying relationships, trends, and correlations, as well as spotting clusters and outliers. +* The dots on the plot shows how the variables are related. A scatter plot is made with the matplotlib library's `scatter() method`. +## Syntax +**Here's how to write code for the scatter() method:** +``` +matplotlib.pyplot.scatter (x_axis_value, y_axis_value, s = None, c = None, vmin = None, vmax = None, marker = None, cmap = None, alpha = None, linewidths = None, edgecolors = None) + +``` +## Prerequisites +Scatter plots can be created in Python with Matplotlib's pyplot library. To build a Scatter plot, first import matplotlib. It is a standard convention to import Matplotlib's pyplot library as plt. +``` +import matplotlib.pyplot as plt + +``` +## Creating a simple Scatter Plot +With Pyplot, you can use the `scatter()` function to draw a scatter plot. + +The `scatter()` function plots one dot for each observation. It needs two arrays of the same length, one for the values of the x-axis, and one for values on the y-axis: +``` +import matplotlib.pyplot as plt +import numpy as np + +x = np.array([5,7,8,7,2,17,2,9,4,11,12,9,6]) +y = np.array([99,86,87,88,111,86,103,87,94,78,77,85,86]) + +plt.scatter(x, y) +plt.show() +``` + +When executed, this will show the following Scatter plot: + + + +## Compare Plots + +In a scatter plot, comparing plots involves examining multiple sets of points to identify differences or similarities in patterns, trends, or correlations between the data sets. + +``` +import matplotlib.pyplot as plt +import numpy as np + +#day one, the age and speed of 13 cars: +x = np.array([5,7,8,7,2,17,2,9,4,11,12,9,6]) +y = np.array([99,86,87,88,111,86,103,87,94,78,77,85,86]) +plt.scatter(x, y) + +#day two, the age and speed of 15 cars: +x = np.array([2,2,8,1,15,8,12,9,7,3,11,4,7,14,12]) +y = np.array([100,105,84,105,90,99,90,95,94,100,79,112,91,80,85]) +plt.scatter(x, y) + +plt.show() +``` + +When executed, this will show the following Compare Scatter plot: + +## Colors in Scatter plot +You can set your own color for each scatter plot with the `color` or the `c` argument: + +``` +import matplotlib.pyplot as plt +import numpy as np + +x = np.array([5,7,8,7,2,17,2,9,4,11,12,9,6]) +y = np.array([99,86,87,88,111,86,103,87,94,78,77,85,86]) +plt.scatter(x, y, color = 'hotpink') + +x = np.array([2,2,8,1,15,8,12,9,7,3,11,4,7,14,12]) +y = np.array([100,105,84,105,90,99,90,95,94,100,79,112,91,80,85]) +plt.scatter(x, y, color = '#88c999') + +plt.show() +``` + +When executed, this will show the following Colors Scatter plot: + +## Color Each Dot +You can even set a specific color for each dot by using an array of colors as value for the `c` argument: + +``**Note:** You cannot use the `color` argument for this, only the `c` argument.`` + +``` +import matplotlib.pyplot as plt +import numpy as np + +x = np.array([5,7,8,7,2,17,2,9,4,11,12,9,6]) +y = np.array([99,86,87,88,111,86,103,87,94,78,77,85,86]) +colors = np.array(["red","green","blue","yellow","pink","black","orange","purple","beige","brown","gray","cyan","magenta"]) + +plt.scatter(x, y, c=colors) + +plt.show() +``` + +When executed, this will show the following Color Each Dot: + +## ColorMap +The Matplotlib module has a number of available colormaps. + +A colormap is like a list of colors, where each color has a value that ranges from 0 to 100. + +Here is an example of a colormap: + + + + +This colormap is called 'viridis' and as you can see it ranges from 0, which is a purple color, up to 100, which is a yellow color. + +## How to Use the ColorMap +You can specify the colormap with the keyword argument `cmap` with the value of the colormap, in this case `'viridis'` which is one of the built-in colormaps available in Matplotlib. + +In addition you have to create an array with values (from 0 to 100), one value for each point in the scatter plot: + +``` +import matplotlib.pyplot as plt +import numpy as np + +x = np.array([5,7,8,7,2,17,2,9,4,11,12,9,6]) +y = np.array([99,86,87,88,111,86,103,87,94,78,77,85,86]) +colors = np.array([0, 10, 20, 30, 40, 45, 50, 55, 60, 70, 80, 90, 100]) + +plt.scatter(x, y, c=colors, cmap='viridis') + +plt.show() +``` + +When executed, this will show the following Scatter ColorMap: + + + +You can include the colormap in the drawing by including the `plt.colorbar()` statement: + +``` +import matplotlib.pyplot as plt +import numpy as np + +x = np.array([5,7,8,7,2,17,2,9,4,11,12,9,6]) +y = np.array([99,86,87,88,111,86,103,87,94,78,77,85,86]) +colors = np.array([0, 10, 20, 30, 40, 45, 50, 55, 60, 70, 80, 90, 100]) + +plt.scatter(x, y, c=colors, cmap='viridis') + +plt.colorbar() + +plt.show() +``` + +When executed, this will show the following Scatter ColorMap using `plt.colorbar()`: + + + + + + From edd8aec3a2b1f9855e7456d0065520d9a43243e2 Mon Sep 17 00:00:00 2001 From: rohit Date: Tue, 4 Jun 2024 00:28:41 +0530 Subject: [PATCH 25/47] Added K-Nearest Neighbors (KNN).md file --- .../K-nearest neighbor (KNN).md | 122 ++++++++++++++++++ contrib/machine-learning/index.md | 1 + 2 files changed, 123 insertions(+) create mode 100644 contrib/machine-learning/K-nearest neighbor (KNN).md diff --git a/contrib/machine-learning/K-nearest neighbor (KNN).md b/contrib/machine-learning/K-nearest neighbor (KNN).md new file mode 100644 index 0000000..748f808 --- /dev/null +++ b/contrib/machine-learning/K-nearest neighbor (KNN).md @@ -0,0 +1,122 @@ +# K-Nearest Neighbors (KNN) Machine Learning Algorithm in Python + +## Introduction +K-Nearest Neighbors (KNN) is a simple, yet powerful, supervised machine learning algorithm used for both classification and regression tasks. It assumes that similar things exist in close proximity. In other words, similar data points are near to each other. + +## How KNN Works +KNN works by finding the distances between a query and all the examples in the data, selecting the specified number of examples (K) closest to the query, then voting for the most frequent label (in classification) or averaging the labels (in regression). + +### Steps: +1. **Choose the number K of neighbors** +2. **Calculate the distance** between the query-instance and all the training samples +3. **Sort the distances** and determine the nearest neighbors based on the K-th minimum distance +4. **Gather the labels** of the nearest neighbors +5. **Vote for the most frequent label** (in case of classification) or **average the labels** (in case of regression) + +## When to Use KNN +### Advantages: +- **Simple and easy to understand:** KNN is intuitive and easy to implement. +- **No training phase:** KNN is a lazy learner, meaning there is no explicit training phase. +- **Effective with a small dataset:** KNN performs well with a small number of input variables. + +### Disadvantages: +- **Computationally expensive:** The algorithm becomes significantly slower as the number of examples and/or predictors/independent variables increase. +- **Sensitive to irrelevant features:** All features contribute to the distance equally. +- **Memory-intensive:** Storing all the training data can be costly. + +### Use Cases: +- **Recommender Systems:** Suggest items based on similarity to user preferences. +- **Image Recognition:** Classify images by comparing new images to the training set. +- **Finance:** Predict credit risk or fraud detection based on historical data. + +## KNN in Python + +### Required Libraries +To implement KNN, we need the following Python libraries: +- `numpy` +- `pandas` +- `scikit-learn` +- `matplotlib` (for visualization) + +### Installation +```bash +pip install numpy pandas scikit-learn matplotlib +``` + +### Example Code +Let's implement a simple KNN classifier using the Iris dataset. + +#### Step 1: Import Libraries +```python +import numpy as np +import pandas as pd +from sklearn.model_selection import train_test_split +from sklearn.neighbors import KNeighborsClassifier +from sklearn.metrics import accuracy_score +import matplotlib.pyplot as plt +``` + +#### Step 2: Load Dataset +```python +from sklearn.datasets import load_iris +iris = load_iris() +X = iris.data +y = iris.target +``` + +#### Step 3: Split Dataset +```python +X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) +``` + +#### Step 4: Train KNN Model +```python +knn = KNeighborsClassifier(n_neighbors=3) +knn.fit(X_train, y_train) +``` + +#### Step 5: Make Predictions +```python +y_pred = knn.predict(X_test) +``` + +#### Step 6: Evaluate the Model +```python +accuracy = accuracy_score(y_test, y_pred) +print(f'Accuracy: {accuracy}') +``` + +### Visualization (Optional) +```python +# Plotting the decision boundary for visualization (for 2D data) +h = .02 # step size in the mesh +# Create color maps +cmap_light = plt.cm.RdYlBu +cmap_bold = plt.cm.RdYlBu + +# For simplicity, we take only the first two features of the dataset +X_plot = X[:, :2] +x_min, x_max = X_plot[:, 0].min() - 1, X_plot[:, 0].max() + 1 +y_min, y_max = X_plot[:, 1].min() - 1, y_plot[:, 1].max() + 1 +xx, yy = np.meshgrid(np.arange(x_min, x_max, h), + np.arange(y_min, y_max, h)) + +Z = knn.predict(np.c_[xx.ravel(), yy.ravel()]) +Z = Z.reshape(xx.shape) +plt.figure() +plt.pcolormesh(xx, yy, Z, cmap=cmap_light) + +# Plot also the training points +plt.scatter(X_plot[:, 0], X_plot[:, 1], c=y, edgecolor='k', cmap=cmap_bold) +plt.xlim(xx.min(), xx.max()) +plt.ylim(yy.min(), yy.max()) +plt.title("3-Class classification (k = 3)") +plt.show() +``` + +## Generalization and Considerations +- **Choosing K:** The choice of K is critical. Smaller values of K can lead to noisy models, while larger values make the algorithm computationally expensive and might oversimplify the model. +- **Feature Scaling:** Since KNN relies on distance calculations, features should be scaled (standardized or normalized) to ensure that all features contribute equally to the distance computation. +- **Distance Metrics:** The choice of distance metric (Euclidean, Manhattan, etc.) can affect the performance of the algorithm. + +In conclusion, KNN is a versatile and easy-to-implement algorithm suitable for various classification and regression tasks, particularly when working with small datasets and well-defined features. However, careful consideration should be given to the choice of K, feature scaling, and distance metrics to optimize its performance. \ No newline at end of file diff --git a/contrib/machine-learning/index.md b/contrib/machine-learning/index.md index b6945cd..e5f5371 100644 --- a/contrib/machine-learning/index.md +++ b/contrib/machine-learning/index.md @@ -16,3 +16,4 @@ - [Types_of_Cost_Functions](cost-functions.md) - [Clustering](clustering.md) - [Grid Search](grid-search.md) +- [K-nearest neighbor (KNN)](K-nearest neighbor (KNN).md) \ No newline at end of file From c812fa29ac87b29857bb3c95ffbaeb766c5b5f8e Mon Sep 17 00:00:00 2001 From: Dishika Vaishkiyar <152963337+Dishika18@users.noreply.github.com> Date: Tue, 4 Jun 2024 00:35:40 +0530 Subject: [PATCH 26/47] Update matplotlib-scatter-plot.md --- .../matplotlib-scatter-plot.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/contrib/plotting-visualization/matplotlib-scatter-plot.md b/contrib/plotting-visualization/matplotlib-scatter-plot.md index a9fa500..535a3a3 100644 --- a/contrib/plotting-visualization/matplotlib-scatter-plot.md +++ b/contrib/plotting-visualization/matplotlib-scatter-plot.md @@ -2,7 +2,7 @@ * A scatter plot is a type of data visualization that uses dots to show values for two variables, with one variable on the x-axis and the other on the y-axis. It's useful for identifying relationships, trends, and correlations, as well as spotting clusters and outliers. * The dots on the plot shows how the variables are related. A scatter plot is made with the matplotlib library's `scatter() method`. ## Syntax -**Here's how to write code for the scatter() method:** +**Here's how to write code for the `scatter() method`:** ``` matplotlib.pyplot.scatter (x_axis_value, y_axis_value, s = None, c = None, vmin = None, vmax = None, marker = None, cmap = None, alpha = None, linewidths = None, edgecolors = None) @@ -30,7 +30,7 @@ plt.show() When executed, this will show the following Scatter plot: - +![Basic line Chart](images/simple_scatter.png) ## Compare Plots @@ -55,6 +55,8 @@ plt.show() When executed, this will show the following Compare Scatter plot: +![Compare Plots](images/scatter_compare.png) + ## Colors in Scatter plot You can set your own color for each scatter plot with the `color` or the `c` argument: @@ -75,10 +77,12 @@ plt.show() When executed, this will show the following Colors Scatter plot: +![Colors in Scatter plot](images/scatter_color.png) + ## Color Each Dot You can even set a specific color for each dot by using an array of colors as value for the `c` argument: -``**Note:** You cannot use the `color` argument for this, only the `c` argument.`` +``Note: You cannot use the `color` argument for this, only the `c` argument.`` ``` import matplotlib.pyplot as plt @@ -95,6 +99,8 @@ plt.show() When executed, this will show the following Color Each Dot: +![Color Each Dot](images/scatter_coloreachdot.png) + ## ColorMap The Matplotlib module has a number of available colormaps. @@ -102,8 +108,7 @@ A colormap is like a list of colors, where each color has a value that ranges fr Here is an example of a colormap: - - +![ColorMap](images/img_colorbar.png) This colormap is called 'viridis' and as you can see it ranges from 0, which is a purple color, up to 100, which is a yellow color. @@ -127,7 +132,7 @@ plt.show() When executed, this will show the following Scatter ColorMap: - +![Scatter ColorMap](images/scatter_colormap1.png) You can include the colormap in the drawing by including the `plt.colorbar()` statement: @@ -148,7 +153,7 @@ plt.show() When executed, this will show the following Scatter ColorMap using `plt.colorbar()`: - +![Scatter ColorMap1](images/scatter_colormap2.png) From 93eae0c0c908f7563c096c4563e9ac37a96a9b5e Mon Sep 17 00:00:00 2001 From: Dishika Vaishkiyar <152963337+Dishika18@users.noreply.github.com> Date: Tue, 4 Jun 2024 00:38:23 +0530 Subject: [PATCH 27/47] Update index.md --- contrib/plotting-visualization/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/plotting-visualization/index.md b/contrib/plotting-visualization/index.md index 3192f03..7e43d9b 100644 --- a/contrib/plotting-visualization/index.md +++ b/contrib/plotting-visualization/index.md @@ -5,5 +5,6 @@ - [Bar Plots in Matplotlib](matplotlib-bar-plots.md) - [Pie Charts in Matplotlib](matplotlib-pie-charts.md) - [Line Charts in Matplotlib](matplotlib-line-plots.md) +- [Scatter Plots in Matplotlib](matplotlib-scatter-plot.md) - [Introduction to Seaborn and Installation](seaborn-intro.md) - [Getting started with Seaborn](seaborn-basics.md) From 5678bc9cf3bfb93c1d938d56b06c11a36e3f94b1 Mon Sep 17 00:00:00 2001 From: Kosuri Indu Date: Tue, 4 Jun 2024 08:19:32 +0530 Subject: [PATCH 28/47] Added Hashing through linear probing --- .../ds-algorithms/hashing-linear-probing.md | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 contrib/ds-algorithms/hashing-linear-probing.md diff --git a/contrib/ds-algorithms/hashing-linear-probing.md b/contrib/ds-algorithms/hashing-linear-probing.md new file mode 100644 index 0000000..0d27db4 --- /dev/null +++ b/contrib/ds-algorithms/hashing-linear-probing.md @@ -0,0 +1,139 @@ +# Hashing with Linear Probing + +In Data Structures and Algorithms, hashing is used to map data of arbitrary size to fixed-size values. A common approach to handle collisions in hashing is **linear probing**. In linear probing, if a collision occurs (i.e., the hash value points to an already occupied slot), we linearly probe through the table to find the next available slot. This method ensures that every element can be inserted or found in the hash table. + +## Points to be Remembered + +- **Hash Function**: A function that converts an input (or 'key') into an index in a hash table. +- **Collision**: When two keys hash to the same index. +- **Linear Probing**: A method to resolve collisions by checking the next slot (i.e., index + 1) until an empty slot is found. + +## Real Life Examples of Hashing with Linear Probing + +- **Student Record System**: Each student record is stored in a table where the student's ID number is hashed to an index. If two students have the same hash index, linear probing finds the next available slot. +- **Library System**: Books are indexed by their ISBN numbers. If two books hash to the same slot, linear probing helps find another spot for the book in the catalog. + +## Applications of Hashing + +Hashing is widely used in Computer Science: + +- **Database Indexing** +- **Caches** (like CPU caches, web caches) +- **Associative Arrays** (or dictionaries in Python) +- **Sets** (unordered collections of unique elements) + +Understanding these applications is essential for Software Development. + +## Operations in Hash Table with Linear Probing + +Key operations include: + +- **INSERT**: Insert a new element into the hash table. +- **SEARCH**: Find the position of an element in the hash table. +- **DELETE**: Remove an element from the hash table. + +## Implementing Hash Table with Linear Probing in Python + +```python +class HashTable: + def __init__(self, size): + self.size = size + self.table = [None] * size + + def hash_function(self, key): + return key % self.size + + def insert(self, key, value): + hash_index = self.hash_function(key) + + if self.table[hash_index] is None: + self.table[hash_index] = (key, value) + else: + while self.table[hash_index] is not None: + hash_index = (hash_index + 1) % self.size + self.table[hash_index] = (key, value) + + def search(self, key): + hash_index = self.hash_function(key) + + while self.table[hash_index] is not None: + if self.table[hash_index][0] == key: + return self.table[hash_index][1] + hash_index = (hash_index + 1) % self.size + + return None + + def delete(self, key): + hash_index = self.hash_function(key) + + while self.table[hash_index] is not None: + if self.table[hash_index][0] == key: + self.table[hash_index] = None + return True + hash_index = (hash_index + 1) % self.size + + return False + + def display(self): + for index, item in enumerate(self.table): + print(f"Index {index}: {item}") + +# Example usage +hash_table = HashTable(10) + +hash_table.insert(1, 'A') +hash_table.insert(11, 'B') +hash_table.insert(21, 'C') + +print("Hash Table after Insert operations:") +hash_table.display() + +print("Search operation for key 11:", hash_table.search(11)) + +hash_table.delete(11) + +print("Hash Table after Delete operation:") +hash_table.display() +``` + +## Output + +```markdown +Hash Table after Insert operations: +Index 0: None +Index 1: (1, 'A') +Index 2: None +Index 3: None +Index 4: None +Index 5: None +Index 6: None +Index 7: None +Index 8: None +Index 9: None +Index 10: None +Index 11: (11, 'B') +Index 12: (21, 'C') + +Search operation for key 11: B + +Hash Table after Delete operation: +Index 0: None +Index 1: (1, 'A') +Index 2: None +Index 3: None +Index 4: None +Index 5: None +Index 6: None +Index 7: None +Index 8: None +Index 9: None +Index 10: None +Index 11: None +Index 12: (21, 'C') +``` + +## Complexity Analysis + +- **Insertion**: Average case O(1), Worst case O(n) when many collisions occur. +- **Search**: Average case O(1), Worst case O(n) when many collisions occur. +- **Deletion**: Average case O(1), Worst case O(n) when many collisions occur. \ No newline at end of file From 0699376c4b30dbe5c767c58f184a58e2ecdb6674 Mon Sep 17 00:00:00 2001 From: Mangalya Phaye <141892171+mdphaye@users.noreply.github.com> Date: Tue, 4 Jun 2024 11:07:11 +0530 Subject: [PATCH 29/47] Rename Queues.md to queues.md --- contrib/ds-algorithms/{Queues.md => queues.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename contrib/ds-algorithms/{Queues.md => queues.md} (100%) diff --git a/contrib/ds-algorithms/Queues.md b/contrib/ds-algorithms/queues.md similarity index 100% rename from contrib/ds-algorithms/Queues.md rename to contrib/ds-algorithms/queues.md From f7dc61226c88c3f877d473cb71ca4142a5e7cad5 Mon Sep 17 00:00:00 2001 From: Pradnya Gaitonde <116059908+PradnyaGaitonde@users.noreply.github.com> Date: Wed, 5 Jun 2024 00:33:22 +0530 Subject: [PATCH 30/47] Create Type_Hinting.md Added Content on Type hinting in python --- contrib/advanced-python/Type_Hinting.md | 106 ++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 contrib/advanced-python/Type_Hinting.md diff --git a/contrib/advanced-python/Type_Hinting.md b/contrib/advanced-python/Type_Hinting.md new file mode 100644 index 0000000..fcf1e1c --- /dev/null +++ b/contrib/advanced-python/Type_Hinting.md @@ -0,0 +1,106 @@ +# Introduction to Type Hinting in Python +Type hinting is a feature in Python that allows you to specify the expected data types of variables, function arguments, and return values. It was introduced +in Python 3.5 via PEP 484 and has since become a standard practice to improve code readability and facilitate static analysis tools. + +**Benefits of Type Hinting** + +1. Improved Readability: Type hints make it clear what type of data is expected, making the code easier to understand for others and your future self. +2. Error Detection: Static analysis tools like MyPy can use type hints to detect type errors before runtime, reducing bugs and improving code quality. +3.Better Tooling Support: Modern IDEs and editors can leverage type hints to provide better autocompletion, refactoring, and error checking features. +4. Documentation: Type hints serve as a form of documentation, indicating the intended usage of functions and classes. + +**Syntax of Type Hinting**
+Type hints can be added to variables, function arguments, and return values using annotations. + +1. Variable Annotations: + +```bash +age: int = 25 +name: str = "Alice" +is_student: bool = True +``` + +2. Function Annotations: + +```bash +def greet(name: str) -> str: + return f"Hello, {name}!" +``` + +3. Multiple Arguments and Return Types: + +```bash +def add(a: int, b: int) -> int: + return a + b +``` + +4. Optional Types: Use the Optional type from the typing module for values that could be None. + +```bash +from typing import Optional + +def get_user_name(user_id: int) -> Optional[str]: + # Function logic here + return None # Example return value +``` + +5. Union Types: Use the Union type when a variable can be of multiple types. + +```bash +from typing import Union + +def get_value(key: str) -> Union[int, str]: + # Function logic here + return "value" # Example return value +``` + +6. List and Dictionary Types: Use the List and Dict types from the typing module for collections. + +```bash +from typing import List, Dict + +def process_data(data: List[int]) -> Dict[str, int]: + # Function logic here + return {"sum": sum(data)} # Example return value +``` + +7. Type Aliases: Create type aliases for complex types to make the code more readable. + +```bash +from typing import List, Tuple + +Coordinates = List[Tuple[int, int]] + +def draw_shape(points: Coordinates) -> None: + # Function logic here + pass +``` + +**Example of Type Hinting in a Class**
+Here is a more comprehensive example using type hints in a class: + +```bash +from typing import List + +class Student: + def __init__(self, name: str, age: int, grades: List[int]) -> None: + self.name = name + self.age = age + self.grades = grades + + def average_grade(self) -> float: + return sum(self.grades) / len(self.grades) + + def add_grade(self, grade: int) -> None: + self.grades.append(grade) + +# Example usage +student = Student("Alice", 20, [90, 85, 88]) +print(student.average_grade()) # Output: 87.66666666666667 +student.add_grade(92) +print(student.average_grade()) # Output: 88.75 +``` + +### Conclusion +Type hinting in Python enhances code readability, facilitates error detection through static analysis, and improves tooling support. By adopting +type hinting, you can write clearer and more maintainable code, reducing the likelihood of bugs and making your codebase easier to navigate for yourself and others. From 23a7577e92f4d1d618ef6784feec46a4294640f2 Mon Sep 17 00:00:00 2001 From: Pradnya Gaitonde <116059908+PradnyaGaitonde@users.noreply.github.com> Date: Wed, 5 Jun 2024 00:35:53 +0530 Subject: [PATCH 31/47] Update index.md Updated index for Type hinting content --- contrib/advanced-python/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/advanced-python/index.md b/contrib/advanced-python/index.md index 5ea5081..e2179e7 100644 --- a/contrib/advanced-python/index.md +++ b/contrib/advanced-python/index.md @@ -1,3 +1,4 @@ # List of sections - [Decorators/\*args/**kwargs](decorator-kwargs-args.md) +- [Type Hinting/\*args/**kwargs](Type_Hinting.md) From a3961ff390a95c24b33bca10b047f89ec63a7201 Mon Sep 17 00:00:00 2001 From: Pradnya Gaitonde <116059908+PradnyaGaitonde@users.noreply.github.com> Date: Wed, 5 Jun 2024 00:44:22 +0530 Subject: [PATCH 32/47] Create Itertools_module.md Added content for itertools module in python. --- contrib/advanced-python/Itertools_module.md | 144 ++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 contrib/advanced-python/Itertools_module.md diff --git a/contrib/advanced-python/Itertools_module.md b/contrib/advanced-python/Itertools_module.md new file mode 100644 index 0000000..501a127 --- /dev/null +++ b/contrib/advanced-python/Itertools_module.md @@ -0,0 +1,144 @@ +# The 'itertools' Module in Python +The itertools module in Python provides a collection of fast, memory-efficient tools that are useful for creating and working with iterators. These functions +allow you to iterate over data in various ways, often combining, filtering, or extending iterators to generate complex sequences efficiently. + +## Benefits of itertools +1. Efficiency: Functions in itertools are designed to be memory-efficient, often generating elements on the fly and avoiding the need to store large intermediate results. +2. Conciseness: Using itertools can lead to more readable and concise code, reducing the need for complex loops and temporary variables. +3. Composability: Functions from itertools can be easily combined, allowing you to build complex iterator pipelines from simple building blocks. + +## Useful Functions in itertools
+Here are some of the most useful functions in the itertools module, along with examples of how to use them: + +1. 'count': Generates an infinite sequence of numbers, starting from a specified value. + +```bash +import itertools + +counter = itertools.count(start=10, step=2) +for _ in range(5): + print(next(counter)) +# Output: 10, 12, 14, 16, 18 +``` + +2. 'cycle': Cycles through an iterable indefinitely. + +```bash +import itertools + +cycler = itertools.cycle(['A', 'B', 'C']) +for _ in range(6): + print(next(cycler)) +# Output: A, B, C, A, B, C +``` + +3.'repeat': Repeats an object a specified number of times or indefinitely. + +```bash +import itertools + +repeater = itertools.repeat('Hello', 3) +for item in repeater: + print(item) +# Output: Hello, Hello, Hello +``` + +4. 'chain': Combines multiple iterables into a single iterable. + +```bash +import itertools + +combined = itertools.chain([1, 2, 3], ['a', 'b', 'c']) +for item in combined: + print(item) +# Output: 1, 2, 3, a, b, c +``` + +5. 'islice': Slices an iterator, similar to slicing a list. + +```bash +import itertools + +sliced = itertools.islice(range(10), 2, 8, 2) +for item in sliced: + print(item) +# Output: 2, 4, 6 +``` + +6. 'compress': Filters elements in an iterable based on a corresponding selector iterable. + +```bash +import itertools + +data = ['A', 'B', 'C', 'D'] +selectors = [1, 0, 1, 0] +result = itertools.compress(data, selectors) +for item in result: + print(item) +# Output: A, C +``` + +7. 'permutations': Generates all possible permutations of an iterable. + +```bash +import itertools + +perms = itertools.permutations('ABC', 2) +for item in perms: + print(item) +# Output: ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B') +``` + +8. 'combinations': Generates all possible combinations of a specified length from an iterable. + +```bash +import itertools + +combs = itertools.combinations('ABC', 2) +for item in combs: + print(item) +# Output: ('A', 'B'), ('A', 'C'), ('B', 'C') +``` + +9. 'product': Computes the Cartesian product of input iterables. + +```bash +import itertools + +prod = itertools.product('AB', '12') +for item in prod: + print(item) +# Output: ('A', '1'), ('A', '2'), ('B', '1'), ('B', '2') +``` + +10. 'groupby': Groups elements of an iterable by a specified key function. + +```bash +import itertools + +data = [{'name': 'Alice', 'age': 25}, {'name': 'Bob', 'age': 25}, {'name': 'Charlie', 'age': 30}] +sorted_data = sorted(data, key=lambda x: x['age']) +grouped = itertools.groupby(sorted_data, key=lambda x: x['age']) +for key, group in grouped: + print(key, list(group)) +# Output: +# 25 [{'name': 'Alice', 'age': 25}, {'name': 'Bob', 'age': 25}] +# 30 [{'name': 'Charlie', 'age': 30}] +``` + +11. 'accumulate': Makes an iterator that returns accumulated sums, or accumulated results of other binary functions specified via the optional func argument. + +```bash +import itertools +import operator + +data = [1, 2, 3, 4, 5] +acc = itertools.accumulate(data, operator.mul) +for item in acc: + print(item) +# Output: 1, 2, 6, 24, 120 +``` + +## Conclusion +The itertools module is a powerful toolkit for working with iterators in Python. Its functions enable efficient and concise handling of iterable data, allowing you to create complex data processing pipelines with minimal memory overhead. +By leveraging itertools, you can improve the readability and performance of your code, making it a valuable addition to your Python programming arsenal. From 294afa2d325da4ce3afff3bf193a286f72832be0 Mon Sep 17 00:00:00 2001 From: Pradnya Gaitonde <116059908+PradnyaGaitonde@users.noreply.github.com> Date: Wed, 5 Jun 2024 00:46:53 +0530 Subject: [PATCH 33/47] Update index.md Updated index for itertools module content. --- contrib/advanced-python/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/advanced-python/index.md b/contrib/advanced-python/index.md index 5ea5081..f8a366f 100644 --- a/contrib/advanced-python/index.md +++ b/contrib/advanced-python/index.md @@ -1,3 +1,4 @@ # List of sections - [Decorators/\*args/**kwargs](decorator-kwargs-args.md) +- ['itertools' module](Itertools_module.md) From 7a83f1524a4c4e5a1c6b27401d98b53fcc5492c4 Mon Sep 17 00:00:00 2001 From: Pradnya Gaitonde <116059908+PradnyaGaitonde@users.noreply.github.com> Date: Wed, 5 Jun 2024 00:48:20 +0530 Subject: [PATCH 34/47] Update index.md --- contrib/advanced-python/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/advanced-python/index.md b/contrib/advanced-python/index.md index e2179e7..36bd103 100644 --- a/contrib/advanced-python/index.md +++ b/contrib/advanced-python/index.md @@ -1,4 +1,4 @@ # List of sections - [Decorators/\*args/**kwargs](decorator-kwargs-args.md) -- [Type Hinting/\*args/**kwargs](Type_Hinting.md) +- [Type Hinting](Type_Hinting.md) From bccf4eacf8e1364ac1a4229f08c7c9d8d0327f1f Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Thu, 6 Jun 2024 05:55:26 +0530 Subject: [PATCH 35/47] Update hierarchical-clustering.md --- .../hierarchical-clustering.md | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/contrib/machine-learning/hierarchical-clustering.md b/contrib/machine-learning/hierarchical-clustering.md index 3f9e606..9382270 100644 --- a/contrib/machine-learning/hierarchical-clustering.md +++ b/contrib/machine-learning/hierarchical-clustering.md @@ -2,20 +2,6 @@ Hierarchical Clustering is a method of cluster analysis that seeks to build a hierarchy of clusters. This README provides an overview of the hierarchical clustering algorithm, including its fundamental concepts, types, steps, and how to implement it using Python. -## Table of Contents - -1. [Introduction](#introduction) -2. [Concepts](#concepts) -3. [Types of Hierarchical Clustering](#types-of-hierarchical-clustering) -4. [Steps in Hierarchical Clustering](#steps-in-hierarchical-clustering) -5. [Linkage Criteria](#linkage-criteria) -6. [Implementation](#implementation) - - [Using Scikit-learn](#using-scikit-learn) - - [Code Example](#code-example) -7. [Evaluation Metrics](#evaluation-metrics) -8. [Conclusion](#conclusion) -9. [References](#references) - ## Introduction Hierarchical Clustering is an unsupervised learning method used to group similar objects into clusters. Unlike other clustering techniques, hierarchical clustering does not require the number of clusters to be specified beforehand. It produces a tree-like structure called a dendrogram, which displays the arrangement of the clusters and their sub-clusters. @@ -111,9 +97,3 @@ print(data.head()) ## Conclusion Hierarchical clustering is a versatile and intuitive method for clustering data. It is particularly useful when the number of clusters is not known beforehand. By understanding the different linkage criteria and evaluation metrics, one can effectively apply hierarchical clustering to various types of data. - -## References - -- [Scikit-learn Documentation](https://scikit-learn.org/stable/modules/clustering.html#hierarchical-clustering) -- [Wikipedia: Hierarchical Clustering](https://en.wikipedia.org/wiki/Hierarchical_clustering) -- [Towards Data Science: Hierarchical Clustering Explained](https://towardsdatascience.com/hierarchical-clustering-explained-925d9e1600c1) From c6c8ffe1f694f2795c468afac8655059146a2d1c Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Thu, 6 Jun 2024 06:01:22 +0530 Subject: [PATCH 36/47] Update transformers.md --- contrib/machine-learning/transformers.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/contrib/machine-learning/transformers.md b/contrib/machine-learning/transformers.md index 0dcf697..7d4fa38 100644 --- a/contrib/machine-learning/transformers.md +++ b/contrib/machine-learning/transformers.md @@ -6,10 +6,12 @@ mechanism. Before transformers, predecessors of attention mechanism were added t Transformers are a revolutionary approach to natural language processing (NLP). Unlike older models, they excel at understanding long-range connections between words. This "attention" mechanism lets them grasp the context of a sentence, making them powerful for tasks like machine translation, text summarization, and question answering. Introduced in 2017, transformers are now the backbone of many large language models, including tools you might use every day. Their ability to handle complex relationships in language is fueling advancements in AI across various fields. ## Model Architecture -

- Model Architecture
-Source: Attention Is All You Need - Figure 1 -

+ +![Model Architecture](assets/transformer-architecture.png) + + +Source: [Attention Is All You Need](https://arxiv.org/pdf/1706.03762) + ### Encoder The encoder is composed of a stack of identical layers. Each layer has two sub-layers. The first is a multi-head self-attention mechanism, and the second is a simple, positionwise fully connected feed-forward network. Each encoder consists of two major components: a self-attention mechanism and a feed-forward neural network. The self-attention mechanism accepts input encodings from the previous encoder and weights their relevance to each other to generate output encodings. The feed-forward neural network further processes each output encoding individually. These output encodings are then passed to the next encoder as its input, as well as to the decoders. From 3d52c978c52da5c0120cb73b4be8ee77d9810613 Mon Sep 17 00:00:00 2001 From: SAM <60264918+SAM-DEV007@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:56:27 +0530 Subject: [PATCH 37/47] Update transformers.md Replaced html with latex equation outside the blockquotes --- contrib/machine-learning/transformers.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/contrib/machine-learning/transformers.md b/contrib/machine-learning/transformers.md index 7d4fa38..95ccada 100644 --- a/contrib/machine-learning/transformers.md +++ b/contrib/machine-learning/transformers.md @@ -9,7 +9,6 @@ Transformers are a revolutionary approach to natural language processing (NLP). ![Model Architecture](assets/transformer-architecture.png) - Source: [Attention Is All You Need](https://arxiv.org/pdf/1706.03762) @@ -21,12 +20,12 @@ The decoder is also composed of a stack of identical layers. In addition to the ### Attention #### Scaled Dot-Product Attention -The input consists of queries and keys of dimension dk, and values of dimension dv. We compute the dot products of the query with all keys, divide each by √dk, and apply a softmax function to obtain the weights on the values. +The input consists of queries and keys of dimension $d_k$ , and values of dimension $d_v$. We compute the dot products of the query with all keys, divide each by $\sqrt d_k$ , and apply a softmax function to obtain the weights on the values. > Attention(Q, K, V) = softmax(QKT / √dk) * V #### Multi-Head Attention -Instead of performing a single attention function with dmodel-dimensional keys, values and queries, it is beneficial to linearly project the queries, keys and values h times with different, learned linear projections to dk, dk and dv dimensions, respectively. +Instead of performing a single attention function with $d_{model}$-dimensional keys, values and queries, it is beneficial to linearly project the queries, keys and values h times with different, learned linear projections to $d_k$ , $d_k$ and $d_v$ dimensions, respectively. Multi-head attention allows the model to jointly attend to information from different representation subspaces at different positions. With a single attention head, averaging inhibits this. @@ -41,7 +40,7 @@ where the projections are parameter matrices. #### Masked Attention It may be necessary to cut out attention links between some word-pairs. For example, the decoder for token position -𝑡 should not have access to token position 𝑡+1. +$t$ should not have access to token position $t+1$. > MaskedAttention(Q, K, V) = softmax(M + (QKT / √dk)) * V From b230028124bcc03f56ed8f87ebeb437a38bce21c Mon Sep 17 00:00:00 2001 From: SAM <60264918+SAM-DEV007@users.noreply.github.com> Date: Thu, 6 Jun 2024 14:17:40 +0530 Subject: [PATCH 38/47] Update transformers.md Mathematical equations are converted to LaTex mathematical equations. --- contrib/machine-learning/transformers.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/contrib/machine-learning/transformers.md b/contrib/machine-learning/transformers.md index 95ccada..5a27688 100644 --- a/contrib/machine-learning/transformers.md +++ b/contrib/machine-learning/transformers.md @@ -20,9 +20,9 @@ The decoder is also composed of a stack of identical layers. In addition to the ### Attention #### Scaled Dot-Product Attention -The input consists of queries and keys of dimension $d_k$ , and values of dimension $d_v$. We compute the dot products of the query with all keys, divide each by $\sqrt d_k$ , and apply a softmax function to obtain the weights on the values. +The input consists of queries and keys of dimension $d_k$ , and values of dimension $d_v$. We compute the dot products of the query with all keys, divide each by $\sqrt {d_k}$ , and apply a softmax function to obtain the weights on the values. -> Attention(Q, K, V) = softmax(QKT / √dk) * V +$$Attention(Q, K, V) = softmax(\dfrac{QK^T}{\sqrt{d_k}}) \times V$$ #### Multi-Head Attention Instead of performing a single attention function with $d_{model}$-dimensional keys, values and queries, it is beneficial to linearly project the queries, keys and values h times with different, learned linear projections to $d_k$ , $d_k$ and $d_v$ dimensions, respectively. @@ -30,11 +30,11 @@ Instead of performing a single attention function with $d_{model}$-dimensional k Multi-head attention allows the model to jointly attend to information from different representation subspaces at different positions. With a single attention head, averaging inhibits this. -> MultiHead(Q, K, V) = Concat(head1, ..., headh) * WO +$$MultiHead(Q, K, V) = Concat(head_1, _{...}, head_h) \times W^O$$ where, -> headi = Attention(Q * WiQ, K * WiK, V * WiV) +$$head_i = Attention(QW_i^Q, KW_i^K, VW_i^V)$$ where the projections are parameter matrices. @@ -42,20 +42,22 @@ where the projections are parameter matrices. It may be necessary to cut out attention links between some word-pairs. For example, the decoder for token position $t$ should not have access to token position $t+1$. -> MaskedAttention(Q, K, V) = softmax(M + (QKT / √dk)) * V +$$MaskedAttention(Q, K, V) = softmax(M + \dfrac{QK^T}{\sqrt{d_k}}) \times V$$ ### Feed-Forward Network Each of the layers in the encoder and decoder contains a fully connected feed-forward network, which is applied to each position separately and identically. This consists of two linear transformations with a ReLU activation in between. -> FFN(x) = (max(0, (x * W1) + b1) * W2) + b2 + +$$FFN(x) = max(0, xW_1 + b_1)W_2 + b_2$$ ### Positional Encoding A positional encoding is a fixed-size vector representation that encapsulates the relative positions of tokens within a target sequence: it provides the transformer model with information about where the words are in the input sequence. The sine and cosine functions of different frequencies: -> PE(pos,2i) = sin(pos/100002i/dmodel) -> PE(pos,2i+1) = cos(pos/100002i/dmodel) +$$PE(pos,2i) = \sin({\dfrac{pos}{10000^{\dfrac{2i}{d_{model}}}}})$$ + +$$PE(pos,2i) = \cos({\dfrac{pos}{10000^{\dfrac{2i}{d_{model}}}}})$$ ## Implementation ### Theory From 35c8620187ea011e49025d414c0e82fa33d31f62 Mon Sep 17 00:00:00 2001 From: Kosuri Indu Date: Thu, 6 Jun 2024 23:56:03 +0530 Subject: [PATCH 39/47] Added in index.md --- contrib/ds-algorithms/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/ds-algorithms/index.md b/contrib/ds-algorithms/index.md index 1d7293b..30881ac 100644 --- a/contrib/ds-algorithms/index.md +++ b/contrib/ds-algorithms/index.md @@ -13,3 +13,4 @@ - [Stacks in Python](stacks.md) - [Sliding Window Technique](sliding-window.md) - [Trie](trie.md) +- [Hashing through Linear Probing](hashing-linear-probing.md) From 8bafaaa091b06d8cbcd49b607633276ea70d3b01 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 8 Jun 2024 10:20:05 +0530 Subject: [PATCH 40/47] Rename K-nearest neighbor (KNN).md to knn.md --- .../machine-learning/{K-nearest neighbor (KNN).md => knn.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename contrib/machine-learning/{K-nearest neighbor (KNN).md => knn.md} (99%) diff --git a/contrib/machine-learning/K-nearest neighbor (KNN).md b/contrib/machine-learning/knn.md similarity index 99% rename from contrib/machine-learning/K-nearest neighbor (KNN).md rename to contrib/machine-learning/knn.md index 748f808..85578f3 100644 --- a/contrib/machine-learning/K-nearest neighbor (KNN).md +++ b/contrib/machine-learning/knn.md @@ -119,4 +119,4 @@ plt.show() - **Feature Scaling:** Since KNN relies on distance calculations, features should be scaled (standardized or normalized) to ensure that all features contribute equally to the distance computation. - **Distance Metrics:** The choice of distance metric (Euclidean, Manhattan, etc.) can affect the performance of the algorithm. -In conclusion, KNN is a versatile and easy-to-implement algorithm suitable for various classification and regression tasks, particularly when working with small datasets and well-defined features. However, careful consideration should be given to the choice of K, feature scaling, and distance metrics to optimize its performance. \ No newline at end of file +In conclusion, KNN is a versatile and easy-to-implement algorithm suitable for various classification and regression tasks, particularly when working with small datasets and well-defined features. However, careful consideration should be given to the choice of K, feature scaling, and distance metrics to optimize its performance. From 906333954390d915e4c85b92e6ccc95919a878d8 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 8 Jun 2024 10:20:27 +0530 Subject: [PATCH 41/47] Update index.md --- contrib/machine-learning/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/machine-learning/index.md b/contrib/machine-learning/index.md index e5f5371..deafdda 100644 --- a/contrib/machine-learning/index.md +++ b/contrib/machine-learning/index.md @@ -16,4 +16,4 @@ - [Types_of_Cost_Functions](cost-functions.md) - [Clustering](clustering.md) - [Grid Search](grid-search.md) -- [K-nearest neighbor (KNN)](K-nearest neighbor (KNN).md) \ No newline at end of file +- [K-nearest neighbor (KNN)](knn.md) From c7adf3b7c6154849e621124963a7810edcd0c6c0 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 8 Jun 2024 10:28:51 +0530 Subject: [PATCH 42/47] Rename ensemble_learning.md to ensemble-learning.md --- .../{ensemble_learning.md => ensemble-learning.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename contrib/machine-learning/{ensemble_learning.md => ensemble-learning.md} (98%) diff --git a/contrib/machine-learning/ensemble_learning.md b/contrib/machine-learning/ensemble-learning.md similarity index 98% rename from contrib/machine-learning/ensemble_learning.md rename to contrib/machine-learning/ensemble-learning.md index 940bd09..508f45e 100644 --- a/contrib/machine-learning/ensemble_learning.md +++ b/contrib/machine-learning/ensemble-learning.md @@ -137,4 +137,4 @@ print("Classification Report:\n", classification_report(y_test, y_pred)) ``` ## Conclusion -Ensemble Learning is a powerful technique that combines multiple models to improve overall performance. By leveraging the strengths of different models, it provides better accuracy, robustness, and generalization. However, it comes with increased complexity and computational cost. Understanding and implementing ensemble methods can significantly enhance machine learning solutions. \ No newline at end of file +Ensemble Learning is a powerful technique that combines multiple models to improve overall performance. By leveraging the strengths of different models, it provides better accuracy, robustness, and generalization. However, it comes with increased complexity and computational cost. Understanding and implementing ensemble methods can significantly enhance machine learning solutions. From 26b6691bf4de1f29fcf7475f1368a4571a0226ac Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 8 Jun 2024 10:29:21 +0530 Subject: [PATCH 43/47] Update index.md --- contrib/machine-learning/index.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contrib/machine-learning/index.md b/contrib/machine-learning/index.md index e64c95d..8e2d84e 100644 --- a/contrib/machine-learning/index.md +++ b/contrib/machine-learning/index.md @@ -11,8 +11,7 @@ - [TensorFlow.md](tensorFlow.md) - [PyTorch.md](pytorch.md) - [Types of optimizers](Types_of_optimizers.md) -- [Random Forest](Random_Forest.md) -- [Ensemble Learning](ensemble_learning.md) +- [Ensemble Learning](ensemble-learning.md) - [Logistic Regression](logistic-regression.md) - [Clustering](clustering.md) - [Grid Search](grid-search.md) From f637a28ba1c2326adedeea7fdf633f48e2199e2f Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 8 Jun 2024 11:00:46 +0530 Subject: [PATCH 44/47] Update index.md --- contrib/advanced-python/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/advanced-python/index.md b/contrib/advanced-python/index.md index 631423a..f61fdf0 100644 --- a/contrib/advanced-python/index.md +++ b/contrib/advanced-python/index.md @@ -10,4 +10,4 @@ - [Protocols](protocols.md) - [Exception Handling in Python](exception-handling.md) - [Generators](generators.md) -- [List Comprehension](list_comprehension.md) +- [List Comprehension](list-comprehension.md) From c2740251604764cb12945841c828dc0033fbb151 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 8 Jun 2024 11:01:08 +0530 Subject: [PATCH 45/47] Rename list_comprehension.md to list-comprehension.md --- .../{list_comprehension.md => list-comprehension.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename contrib/advanced-python/{list_comprehension.md => list-comprehension.md} (100%) diff --git a/contrib/advanced-python/list_comprehension.md b/contrib/advanced-python/list-comprehension.md similarity index 100% rename from contrib/advanced-python/list_comprehension.md rename to contrib/advanced-python/list-comprehension.md From 98ad137d915cdb5039045aa0ee7f0c696c02ade5 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 8 Jun 2024 11:34:42 +0530 Subject: [PATCH 46/47] Rename Type_Hinting.md to type-hinting.md --- contrib/advanced-python/{Type_Hinting.md => type-hinting.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename contrib/advanced-python/{Type_Hinting.md => type-hinting.md} (100%) diff --git a/contrib/advanced-python/Type_Hinting.md b/contrib/advanced-python/type-hinting.md similarity index 100% rename from contrib/advanced-python/Type_Hinting.md rename to contrib/advanced-python/type-hinting.md From 3e346a29a6bcddd25fe0c7af7b8b2dbffe74a3da Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 8 Jun 2024 11:37:03 +0530 Subject: [PATCH 47/47] Rename Itertools_module.md to itertools.md --- contrib/advanced-python/{Itertools_module.md => itertools.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename contrib/advanced-python/{Itertools_module.md => itertools.md} (100%) diff --git a/contrib/advanced-python/Itertools_module.md b/contrib/advanced-python/itertools.md similarity index 100% rename from contrib/advanced-python/Itertools_module.md rename to contrib/advanced-python/itertools.md