Transformers documentation

Ses Spektrogram Dönüşümü

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.2).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Bu model 2021-04-05 tarihinde HF papers'ta yayımlandı ve 2022-11-21 tarihinde Hugging Face Transformers'a katkıda bulunuldu.

Ses Spektrogram Dönüşümü

FlashAttention SDPA

Genel Bakış

Audio Spectrogram Transformer modeli, Yuan Gong, Yu-An Chung ve James Glass tarafından AST: Audio Spectrogram Transformer makalesinde önerilmiştir. Audio Spectrogram Transformer, sesi bir görüntüye (spektrogram) dönüştürerek Vision Transformer'ı ses verisine uygular. Model, ses sınıflandırma için en iyi sonuçları elde eder.

Makalenin özeti aşağıdaki gibidir:

Geçen on yıl boyunca, konvolüsyonel sinir ağları (CNN'ler), ses spektrogramlarından ilgili etiketlere doğrudan bir eşleme öğrenmeyi amaçlayan uçtan uca ses sınıflandırma modellerinin ana yapı taşı olarak yaygın şekilde benimsenmiştir. Uzun menzilli küresel bağlamı daha iyi yakalamak için son zamanlardaki bir eğilim, CNN'nin üzerine bir öz-dikkat mekanizması ekleyerek CNN-dikkat hibrit modeli oluşturmaktır. Ancak, CNN'ye bağımlılığın gerekli olup olmadığı ve saf olarak dikkate dayalı sinir ağlarının ses sınıflandırmada iyi performans elde etmek için yeterli olup olmadığı belirsizdir. Bu makalede, soruyu Audio Spectrogram Transformer (AST) ile yanıtlandırıyoruz; AST, ses sınıflandırma için ilk konvolüsyonsuz, saf olarak dikkate dayalı modeldir. AST'yi çeşitli ses sınıflandırma kıstaslarında değerlendiriyoruz; model, AudioSet'te 0,485 mAP, ESC-50'de %95,6 ve Speech Commands V2'de %98,1 doğruluk oranlarıyla yeni en iyi sonuçları elde etmektedir.

drawing Audio Spectrogram Transformer architecture. Taken from the original paper.

Bu model nielsr tarafından katkıda bulunmuştur. Orijinal kod burada bulunabilir.

Kullanım ipuçları

  • Kendi veri setinizde Audio Spectrogram Transformer (AST) modelini ince ayar yaparken, girdi normalizasyonunu (girdinin 0 ortalamaya ve 0.5 standart sapmaya sahip olduğundan emin olmak için) sizin yapmanız önerilir. ASTFeatureExtractor bu işlemden sorumludur. Not: Varsayılan olarak AudioSet ortalama ve standart sapma değerlerini kullanır. Yazarların bir alt akış (downstream) veri seti için istatistikleri nasıl hesapladığını görmek için ast/src/get_norm_stats.py dosyasını inceleyebilirsiniz.
  • AST'nin düşük bir öğrenme hızına ihtiyaç duyduğunu unutmayın (yazarlar, PSLA makalesinde önerdikleri CNN modeline kıyasla 10 kat daha küçük bir öğrenme hızı kullanıyor) ve hızlı bir şekilde yakınsıyor; bu nedenle lütfen göreviniz için uygun bir öğrenme hızı ve öğrenme hızı zamanlayıcısı arayın.

Ölçekli Nokta Çarpımı Dikkat (SDPA) Kullanımı

PyTorch, torch.nn.functional parçası olarak yerel ölçekli nokta çarpımı dikkati (SDPA) operatörünü içerir. Bu fonksiyon, girdilere ve kullanılan donanıma bağlı olarak uygulanabilecek çeşitli uygulamaları kapsar. Daha fazla bilgi için resmi dokümantasyonu veya GPU Inference sayfasına bakın.

torch>=2.1.1 için bir uygulama mevcut olduğunda varsayılan olarak SDPA kullanılır, ancak SDPA'nın kullanılmasını açıkça istemek için from_pretrained() içinde attn_implementation="sdpa" ayarlayabilirsiniz.

from transformers import ASTForAudioClassification


model = ASTForAudioClassification.from_pretrained("MIT/ast-finetuned-audioset-10-10-0.4593", attn_implementation="sdpa", device_map="auto")
...

En iyi hızlanmalar için, modelin yarım hassasiyette (ör. torch.float16 veya torch.bfloat16) yüklenmesini öneririz.

Yerel bir benchmark'ta (A100-40GB, PyTorch 2.3.0, OS Ubuntu 22.04) float32 ve MIT/ast-finetuned-audioset-10-10-0.4593 modeliyle, çıkarım sırasında aşağıdaki hızlanmaları gözlemledik.

Toplu işlem boyutuOrtalama çıkarım süresi (ms), aceleci modOrtalama çıkarım süresi (ms), sdpa modeliHızlandırma, Sdpa / Eager (x)
12764.5
21262
42182.62
840142.86

Kaynaklar

Audio Spectrogram Transformer ile başlamanıza yardımcı olmak için resmi Hugging Face ve topluluk (🌎 ile belirtilen) kaynaklarının listesi.

Audio Classification

Buraya bir kaynak eklemek isterseniz, bir Pull Request açmaktan çekinmeyin; inceleyeceğiz! Kaynağın, mevcut bir kaynağı tekrarlamak yerine ideal olarak yeni bir şeyi göstermesi beklenir.

ASTConfig

sınıf transformers.ASTConfig

< >

( transformers_version: str | None = Nonearchitectures: list[str] | None = Noneoutput_hidden_states: bool | None = Falsereturn_dict: bool | None = Truedtype: str | torch.dtype | None = Nonechunk_size_feed_forward: int = 0is_encoder_decoder: bool = Falseid2label: dict[int, str] | dict[str, str] | None = Nonelabel2id: dict[str, int] | dict[str, str] | None = Noneproblem_type: Literal['regression', 'single_label_classification', 'multi_label_classification'] | None = Nonehidden_size: int = 768num_hidden_layers: int = 12num_attention_heads: int = 12intermediate_size: int = 3072hidden_act: str = 'gelu'hidden_dropout_prob: float | int = 0.0attention_probs_dropout_prob: float | int = 0.0initializer_range: float = 0.02layer_norm_eps: float = 1e-12patch_size: int | list[int] | tuple[int, int] = 16qkv_bias: bool = Truefrequency_stride: int = 10time_stride: int = 10max_length: int = 1024num_mel_bins: int = 128 )

Parametreler

  • hidden_size (int, isteğe bağlı, varsayılan 768) — Gizli temsillerin boyutu.
  • num_hidden_layers (int, isteğe bağlı, varsayılan 12) — Transformer çözücüdeki gizli katman sayısı.
  • num_attention_heads (int, isteğe bağlı, varsayılan 12) — Transformer decoder'ındaki her dikkat katmanı için dikkat başı sayısı.
  • intermediate_size (int, isteğe bağlı, varsayılan 3072) — MLP temsillerinin boyutu.
  • hidden_act (str, isteğe bağlı, varsayılan gelu) — Çözücüdeki doğrusal olmayan aktivasyon fonksiyonu (fonksiyon veya dize). Örneğin, "gelu", "relu", "silu" vb.
  • hidden_dropout_prob (Union[float, int], isteğe bağlı, varsayılan 0.0) — Gömme, kodlayıcı ve havuzlayıcıdaki tüm tam bağlı katmanlar için dropout olasılığı.
  • attention_probs_dropout_prob (Union[float, int], isteğe bağlı, varsayılan 0.0) — Dikkat olasılıkları için dropout oranı.
  • initializer_range (float, isteğe bağlı, varsayılan 0.02) — Tüm ağırlık matrislerini başlatmak için kullanılan truncated_normal_initializer'ın standart sapması.
  • layer_norm_eps (float, isteğe bağlı, varsayılan 1e-12) — Katman normalizasyon katmanları tarafından kullanılan epsilon.
  • patch_size (Union[int, list[int], tuple[int, int]], isteğe bağlı, varsayılan 16) — Her yamanın boyutu (çözünürlüğü).
  • qkv_bias (bool, isteğe bağlı, varsayılan True) — Sorgulara, anahtarlara ve değerlere bir sapma eklenip eklenmeyeceği.
  • frequency_stride (int, isteğe bağlı, varsayılan 10) — Spektrogramları yama (patch) haline getirirken kullanılacak frekans adımı.
  • time_stride (int, isteğe bağlı, varsayılan 10) — Spektrogramları yama (patch) haline getirirken kullanılacak zamansal atlama (stride).
  • max_length (int, isteğe bağlı, varsayılan 1024) — Spektrogramların zaman boyutu.
  • num_mel_bins (int, isteğe bağlı, varsayılan 128) — Giriş başına kullanılan mel özellik sayısı. AutoFeatureExtractor sınıfında kullanılan değerle eşleşmelidir.

Bu, bir Audio Spectrogram TransformerModel yapılandırmasını depolamak için kullanılan yapılandırma sınıfıdır. Belirtilen argümanlara göre bir Audio Spectrogram Transformer modeli örneklemek ve model mimarisini tanımlamak için kullanılır. Varsayılan değerlerle bir yapılandırma örneği oluşturmak, MIT/ast-finetuned-audioset-10-10-0.4593 modelinin yapılandırmasına benzer bir yapılandırma üretir.

Yapılandırma nesneleri PreTrainedConfig sınıfından devralır ve model çıktılarını kontrol etmek için kullanılabilir. Daha fazla bilgi için PreTrainedConfig belgesini okuyun.

Örnek:

>>> from transformers import ASTConfig, ASTModel

>>> # Initializing a AST MIT/ast-finetuned-audioset-10-10-0.4593 style configuration
>>> configuration = ASTConfig()

>>> # Initializing a model (with random weights) from the MIT/ast-finetuned-audioset-10-10-0.4593 style configuration
>>> model = ASTModel(configuration)

>>> # Accessing the model configuration
>>> configuration = model.config

ASTFeatureExtractor

sınıf transformers.ASTFeatureExtractor

< >

( feature_size = 1sampling_rate = 16000num_mel_bins = 128max_length = 1024padding_value = 0.0do_normalize = Truemean = -4.2677393std = 4.5689974return_attention_mask = False**kwargs )

Parametreler

  • feature_size (int, isteğe bağlı, varsayılan 1) — Çıkarılan özelliklerin boyutu.
  • sampling_rate (int, isteğe bağlı, varsayılan 16000) — Ses dosyalarının dijitalleştirilmesi gereken örnekleme hızı, hertz (Hz) cinsinden ifade edilir.
  • num_mel_bins (int, isteğe bağlı, varsayılan 128) — Mel frekans kutu sayısı.
  • max_length (int, isteğe bağlı, varsayılan 1024) — Çıkarılan özelliklerin doldurulacağı/kısaltılacağı maksimum uzunluk.
  • do_normalize (bool, isteğe bağlı, varsayılan True) — mean ve std kullanılarak log-Mel özelliklerinin normalize edip edilmeyeceği.
  • mean (float, isteğe bağlı, varsayılan -4.2677393) — Log-Mel özelliklerini normalize etmek için kullanılan ortalama değer. Varsayılan olarak AudioSet ortalamasını kullanır.
  • std (float, isteğe bağlı, varsayılan 4.5689974) — Log-Mel özelliklerini normalize etmek için kullanılan standart sapma değeri. Varsayılan olarak AudioSet standart sapmasını kullanır.
  • return_attention_mask (bool, isteğe bağlı, varsayılan False) — call() attention_mask döndürmeli mi?

Bir Audio Spectrogram Transformer (AST) özellik çıkarıcısı oluşturur.

Bu özellik çıkarıcı, ana yöntemlerin çoğunu içeren SequenceFeatureExtractor sınıfından devralır. Kullanıcıların bu yöntemler hakkında daha fazla bilgi için bu üst sınıfa başvurması gerekir.

Bu sınıf, yüklüyse TorchAudio, değilse numpy kullanarak ham ses verisinden mel-filtre bankası özelliklerini çıkarır, bunları sabit bir uzunluğa kısaltır/uzatır ve ortalama ile standart sapma kullanarak normalize eder.

__call__

< >

( raw_speech: numpy.ndarray | list[float] | list[numpy.ndarray] | list[list[float]]sampling_rate: int | None = Nonereturn_tensors: str | transformers.utils.generic.TensorType | None = None**kwargs )

Parametreler

  • raw_speech (np.ndarray, list[float], list[np.ndarray], list[list[float]]) — Doldurulacak (padding) dizi veya dizi grubu. Her dizi, bir numpy dizisi, bir float değerleri listesi, bir numpy dizileri listesi veya float değerleri listeleri listesi olabilir. Tek kanallı (mono) ses olmalı, stereo değil; yani her zaman adımı için tek bir float değer içermelidir.
  • sampling_rate (int, isteğe bağlı) — raw_speech girdisinin örneklenmiş olduğu örneklem hızı. Sessiz hataları önlemek için ileri çağrıda sampling_rate değerinin geçirilmesi şiddetle önerilir.
  • return_tensors (str veya TensorType, isteğe bağlı) — Belirlenirse, Python tamsayı listesi yerine tensörler döndürülür. Kabul edilen değerler şunlardır:
    • 'pt': PyTorch torch.Tensor nesnelerini döndürür.
    • 'np': Numpy np.ndarray nesnelerini döndürür.

Bir veya birden fazla diziyi model için özelliklendirmek ve hazırlamak için ana yöntem.

ASTModel

sınıf transformers.ASTModel

< >

( config: ASTConfig )

Parametreler

  • config (ASTConfig) — Modelin tüm parametrelerini içeren model yapılandırma sınıfı. Bir yapılandırma dosyasıyla başlatmak, modelle ilişkili ağırlıkları yüklemez, yalnızca yapılandırmayı yükler. Model ağırlıklarını yüklemek için from_pretrained() yöntemine bakın.

Üzerinde herhangi bir özel başlık olmadan ham gizli durumlar (hidden-states) üreten çıplak Audio Spectrogram Transformer Model.

Bu model PreTrainedModel sınıfından devralır. Kütüphanenin tüm modelleri için uyguladığı genel yöntemler (indirme veya kaydetme, giriş gömme boyutlarını yeniden boyutlandırma, başları budama vb.) için üst sınıf belgelendirmesine bakın.

Bu model aynı zamanda bir PyTorch torch.nn.Module alt sınıfıdır. Bunu standart bir PyTorch Module olarak kullanın ve genel kullanım ve davranışla ilgili tüm konular için PyTorch dokümantasyonuna başvurun.

forward

< >

( input_values: typing.Optional[torch.Tensor] = Noneattention_mask: typing.Optional[torch.Tensor] = None**kwargs: *<class 'transformers.utils.generic.TransformersKwargs'> ) → BaseModelOutputWithPooling or tuple(torch.Tensor)

Parametreler

  • input_values (torch.Tensor, şekli (batch_size, max_length, num_mel_bins)) — Ham ses dalgasından çıkarılan mel özelliklerinin kayan nokta değerleri. Ham ses dalgası, bir .flac veya .wav ses dosyasını list[float] tipinde bir diziye, numpy.ndarray veya torch.Tensor tipine yükleyerek elde edilebilir; örneğin torchcodec kütüphanesi (pip install torchcodec) veya soundfile kütüphanesi (pip install soundfile) aracılığıyla. Diziyi input_features için hazırlamak için, mel özelliklerini çıkarmak, dolgu yapmak ve torch.Tensor tipinde bir tensöre dönüştürmek üzere AutoFeatureExtractor kullanılmalıdır. Bkz. call()
  • attention_mask (torch.Tensor şeklinde (batch_size, sequence_length), isteğe bağlı) — Doldurma (padding) token indekslerinde dikkat (attention) işlemi yapmaktan kaçınmak için kullanılan maske. Seçilen maske değerleri [0, 1]:
    • 1, maskelenmemiş jetonlar için,
    • maskelenmiş jetonlar için 0.

    Dikkat maskeleri nedir?

Dönüş değeri

BaseModelOutputWithPooling veya tuple(torch.Tensor)

A BaseModelOutputWithPooling veya bir torch.Tensor demeti (eğer return_dict=False geçirildiyse veya config.return_dict=False ise), yapılandırmaya (ASTConfig) ve girdilere bağlı olarak çeşitli öğelerden oluşur.

ASTModel forward metodu, __call__ özel metodunu geçersiz kılar.

İleri geçiş tarifi bu fonksiyon içinde tanımlanmalı olsa da, sonrasında bunun yerine Module örneğini çağırmak gerekir; çünkü önceki, ön ve son işleme adımlarını çalıştırmaktan sorumluyken ikincisi bunları sessizce yok sayar.

  • last_hidden_state (torch.Tensor, şekli (batch_size, sequence_length, hidden_size)) — Modelin son katmanının çıktısındaki gizli durumlar dizisi.

  • pooler_output (torch.Tensor, şekli (batch_size, hidden_size)) — Sıranın ilk token'ının (sınıflandırma token'ı) son katman gizli durumu, yardımcı ön eğitim görevi için kullanılan katmanlar üzerinden ek işlemden geçirildikten sonraki hali. Örneğin BERT ailesi modelleri için, bu, sınıflandırma token'ının doğrusal bir katman ve tanh aktivasyon fonksiyonu üzerinden işlenmesinden sonra döndürülen değerdir. Doğrusal katman ağırlıkları, ön eğitim sırasında bir sonraki cümle tahmini (sınıflandırma) hedefinden eğitilir.

  • hidden_states (tuple(torch.Tensor), isteğe bağlı, output_hidden_states=True geçirildiğinde veya config.output_hidden_states=True olduğunda döndürülür) — torch.Tensor (modelin bir gömme katmanı varsa gömme katmanının çıktısı için bir tane + her katmanın çıktısı için birer tane) içeren, (batch_size, sequence_length, hidden_size) biçiminde bir demet.

    Her katmanın çıktısında modelin gizli durumları ve isteğe bağlı başlangıç gömme çıktıları.

  • attentions (tuple(torch.Tensor), isteğe bağlı, output_attentions=True geçirildiğinde veya config.output_attentions=True olduğunda döndürülür) — torch.Tensor (katman başına bir tane) içeren bir tuple, şekli (batch_size, num_heads, sequence_length, sequence_length).

    Dikkat softmax'ı sonrası dikkat ağırlıkları, öz-dikkat başlıklarında ağırlıklı ortalamanın hesaplanmasında kullanılır.

ASTForAudioClassification

sınıf transformers.ASTForAudioClassification

< >

( config: ASTConfig )

Parametreler

  • config (ASTConfig) — Modelin tüm parametrelerini içeren model yapılandırma sınıfı. Bir yapılandırma dosyasıyla başlatmak, modelle ilişkili ağırlıkları yüklemez, yalnızca yapılandırmayı yükler. Model ağırlıklarını yüklemek için from_pretrained() yöntemine bakın.

Üstünde bir ses sınıflandırma başlığı (toplanmış çıktının üzerinde doğrusal bir katman) bulunan Audio Spectrogram Transformer modeli, örneğin AudioSet, Speech Commands v2 gibi veri setleri için.

Bu model PreTrainedModel sınıfından devralır. Kütüphanenin tüm modelleri için uyguladığı genel yöntemler (indirme veya kaydetme, giriş gömme boyutlarını yeniden boyutlandırma, başları budama vb.) için üst sınıf belgelendirmesine bakın.

Bu model aynı zamanda bir PyTorch torch.nn.Module alt sınıfıdır. Bunu standart bir PyTorch Module olarak kullanın ve genel kullanım ve davranışla ilgili tüm konular için PyTorch dokümantasyonuna başvurun.

forward

< >

( input_values: typing.Optional[torch.Tensor] = Nonelabels: typing.Optional[torch.Tensor] = Noneattention_mask: typing.Optional[torch.Tensor] = None**kwargs: *<class 'transformers.utils.generic.TransformersKwargs'> ) → SequenceClassifierOutput or tuple(torch.Tensor)

Parametreler

  • input_values (torch.Tensor, şekli (batch_size, max_length, num_mel_bins)) — Ham ses dalgacığından çıkarılan mel özelliklerinin kayan nokta değerleri. Ham ses dalgacığı, bir .flac veya .wav ses dosyasını list[float] tipinde bir diziye, numpy.ndarray veya torch.Tensor içine yükleyerek elde edilebilir; örneğin torchcodec kütüphanesi (pip install torchcodec) veya soundfile kütüphanesi (pip install soundfile) aracılığıyla. Diziyi input_features için hazırlamak için, mel özelliklerini çıkarmak, dolgu yapmak ve torch.Tensor tipinde bir tensöre dönüştürmek üzere AutoFeatureExtractor kullanılmalıdır. Bkz. call()
  • labels (torch.LongTensor, şekli (batch_size,), isteğe bağlı) — Ses sınıflandırma/geri dönüşüm kaybını hesaplamak için etiketler. Endeksler [0, ..., config.num_labels - 1] aralığında olmalıdır. config.num_labels == 1 ise bir geri dönüşüm kaybı (Ortalama Kare kaybı) hesaplanır, config.num_labels > 1 ise bir sınıflandırma kaybı (Çapraz Entropi) hesaplanır.
  • attention_mask (torch.Tensor şeklinde (batch_size, sequence_length), isteğe bağlı) — Doldurma (padding) token indekslerinde dikkat (attention) işlemi yapmaktan kaçınmak için kullanılan maske. Seçilen maske değerleri [0, 1]:
    • 1, maskelenmemiş jetonlar için,
    • maskelenmiş jetonlar için 0.

    Dikkat maskeleri nedir?

Dönüş değeri

SequenceClassifierOutput veya tuple(torch.Tensor)

Bir SequenceClassifierOutput veya torch.Tensor demeti (return_dict=False geçirildiğinde veya config.return_dict=False olduğunda), yapılandırmaya (ASTConfig) ve girdilere bağlı olarak çeşitli öğelerden oluşur.

ASTForAudioClassification forward metodu, __call__ özel metodunu geçersiz kılar.

İleri geçiş tarifi bu fonksiyon içinde tanımlanmalı olsa da, sonrasında bunun yerine Module örneğini çağırmak gerekir; çünkü önceki, ön ve son işleme adımlarını çalıştırmaktan sorumluyken ikincisi bunları sessizce yok sayar.

  • loss (torch.Tensor, şekli (1,), isteğe bağlı, labels sağlandığında döndürülür) — Sınıflandırma (config.num_labels==1 ise regresyon) kaybı.

  • logits (torch.Tensor, şekli (batch_size, config.num_labels)) — Sınıflandırma (veya config.num_labels==1 ise regresyon) puanları (SoftMax öncesi).

  • hidden_states (tuple(torch.Tensor), isteğe bağlı, output_hidden_states=True geçirildiğinde veya config.output_hidden_states=True olduğunda döndürülür) — torch.Tensor (modelin bir gömme katmanı varsa gömme katmanının çıktısı için bir tane + her katmanın çıktısı için birer tane) içeren, (batch_size, sequence_length, hidden_size) biçiminde bir demet.

    Her katmanın çıktısında modelin gizli durumları ve isteğe bağlı başlangıç gömme çıktıları.

  • attentions (tuple(torch.Tensor), isteğe bağlı, output_attentions=True geçirildiğinde veya config.output_attentions=True olduğunda döndürülür) — torch.Tensor (katman başına bir tane) içeren bir tuple, şekli (batch_size, num_heads, sequence_length, sequence_length).

    Dikkat softmax'ı sonrası dikkat ağırlıkları, öz-dikkat başlıklarında ağırlıklı ortalamanın hesaplanmasında kullanılır.

Örnek:

>>> from transformers import AutoFeatureExtractor, ASTForAudioClassification
>>> from datasets import load_dataset
>>> import torch

>>> dataset = load_dataset("hf-internal-testing/librispeech_asr_demo", "clean", split="validation")
>>> dataset = dataset.sort("id")
>>> sampling_rate = dataset.features["audio"].sampling_rate

>>> feature_extractor = AutoFeatureExtractor.from_pretrained("MIT/ast-finetuned-audioset-10-10-0.4593")
>>> model = ASTForAudioClassification.from_pretrained("MIT/ast-finetuned-audioset-10-10-0.4593")

>>> # audio file is decoded on the fly
>>> inputs = feature_extractor(dataset[0]["audio"]["array"], sampling_rate=sampling_rate, return_tensors="pt")

>>> with torch.no_grad():
...     logits = model(**inputs).logits

>>> predicted_class_ids = torch.argmax(logits, dim=-1).item()
>>> predicted_label = model.config.id2label[predicted_class_ids]
>>> predicted_label
...

>>> # compute loss - target_label is e.g. "down"
>>> target_label = model.config.id2label[0]
>>> inputs["labels"] = torch.tensor([model.config.label2id[target_label]])
>>> loss = model(**inputs).loss
>>> round(loss.item(), 2)
...
Update on GitHub