Skip to content

Commit a6ca885

Browse files
🚀 Release 0.4.0 (#134)
2 parents 424cd06 + 6f8720a commit a6ca885

197 files changed

Lines changed: 50702 additions & 6946 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,40 @@ All notable changes to this project will be documented in this file.
44

55
## [unreleased]
66

7+
## 0.4.0 (2024-09-01)
8+
9+
### Features
10+
11+
🚀 **examples:** integrate Gemma2-2B ([#132](https://github.com/owkin/GrAIdient/pull/132))\
12+
**layer_seq:** LLM sliding window ([#131](https://github.com/owkin/GrAIdient/pull/131))\
13+
🚀 **examples:** 3 LLMs examples ([#130](https://github.com/owkin/GrAIdient/pull/130))\
14+
**layer_seq:** LLM generate ([128](https://github.com/owkin/GrAIdient/pull/128))\
15+
**layer_seq:** MultiplySeq, SiLU & LLM test ([127](https://github.com/owkin/GrAIdient/pull/127))\
16+
**layer_seq:** ValueCausalSeq ([126](https://github.com/owkin/GrAIdient/pull/126))\
17+
**layer_seq:** QueryCausalSeq ([125](https://github.com/owkin/GrAIdient/pull/125))\
18+
**layer_seq:** RoPESeq ([124](https://github.com/owkin/GrAIdient/pull/124))\
19+
**layer_seq:** RMSNormSeq ([123](https://github.com/owkin/GrAIdient/pull/123))\
20+
**layer_seq:** EmbeddingSeq ([122](https://github.com/owkin/GrAIdient/pull/122))\
21+
🪜 **feat:** LayerCAM2D -> VQGrad2D, LayerCAMSeq -> VQGradSeq ([#117](https://github.com/owkin/GrAIdient/pull/117))\
22+
⚙️ **core:** GELU vs GELUApprox ([113](https://github.com/owkin/GrAIdient/pull/113))\
23+
🚀 **perf:** QuerySelf & ValueSelf ([112](https://github.com/owkin/GrAIdient/pull/112))\
24+
🚀 **perf:** benchmark ViT base model ([111](https://github.com/owkin/GrAIdient/pull/111))\
25+
⚙️ **core:** initForward,Backward model API ([109](https://github.com/owkin/GrAIdient/pull/109))\
26+
🪜 **layer_1d:** Dropout1D ([#108](https://github.com/owkin/GrAIdient/pull/108))\
27+
🪜 **feat:** VQGrad, VQGradSeq ([#107](https://github.com/owkin/GrAIdient/pull/107))
28+
29+
### Bug Fixes
30+
31+
🐛 **fix:** run on Apple Silicon ([110](https://github.com/owkin/GrAIdient/pull/110))
32+
33+
### Miscellaneous Tasks
34+
35+
📚 **docs:** LLM doc & split tests ([129](https://github.com/owkin/GrAIdient/pull/129))\
36+
🚀 **perf:** use half in Metal kernels ([121](https://github.com/owkin/GrAIdient/pull/121))\
37+
🔨 **refactor:** handle float16 along float on GPU ([#120](https://github.com/owkin/GrAIdient/pull/120))\
38+
🚀 **perf:** copy & generate weights faster ([119](https://github.com/owkin/GrAIdient/pull/119))\
39+
🚀 **perf:** Convolution2D ([118](https://github.com/owkin/GrAIdient/pull/118))
40+
741
## 0.3.1 (2023-08-09)
842

943
### Bug Fixes

Docs/Contributing/CONTRIBUTING.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,14 @@ containing the commits to merge into the `main` branch.
248248
Do not delete the "Unreleased" section title: future PRs will insert
249249
changelog items in this section.
250250
- Commit and push the changes.
251-
- Squash and merge the new branch into `release_N`.
251+
- Squash and merge the new branch into `release_N` with title \
252+
🔧 chore: update changelog
252253

253254
1. Create a Pull Request for `release_N` targeting the `main` branch.
254255

255256
1. Review and Merge the Pull Request, change the commit
256257
message \
257-
🔧 chore: release X.Y.Z
258+
🚀 Release X.Y.Z
258259

259260
1. Create a GitHub release X.Y.Z from `main`:
260261
- GitHub > Releases > Draft new Release

Docs/Examples/AutoEncoder.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,19 @@ conda env remove --name graiexamples
6464

6565
## Steps
6666

67-
1. Dump the training dataset.
67+
Each train example uses a `CIFARAutoEncoderTrainer`.
68+
The latter is responsible for initializing the training dataset
69+
before the actual training takes place.
70+
6871
1. Train a simple auto encoder model.
6972
1. Train a UNet like auto encoder model.
7073
1. Train a StyleGAN like auto encoder model.
74+
75+
## Further tests
76+
77+
Further tests are available at
78+
[AutoEncoderTests](../../Tests/GrAIExamples/AutoEncoderTests.swift).
79+
80+
The test `testTrain` compares the training of a `SimpleAutoEncoder`
81+
in GrAIdient and in PyTorch to show that the same `loss` is computed
82+
throughout the training.

Docs/Examples/EXAMPLES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ The following examples are currently available:
1212
- [VGG](VGG.md)
1313
- [Vision Transformer](VisionTransformer.md)
1414
- [Auto Encoder](AutoEncoder.md)
15+
- [LLM](LLM.md)

Docs/Examples/LLM.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# 🚀 LLM Example
2+
3+
This is the documentation for running
4+
[LLMs](../../Tests/GrAIExamples/LLMExample.swift) on the GPU.
5+
6+
## Setup
7+
8+
This example has some `Python` dependencies. In order to run
9+
the example, we first have to setup the environment:
10+
11+
```bash
12+
conda create --name graiexamples python=3.9
13+
conda activate graiexamples
14+
cd Tests/GrAIExamples/Base
15+
pip install -e .
16+
```
17+
18+
Then:
19+
- Download weights from
20+
[MistralAI](https://docs.mistral.ai/getting-started/open_weight_models/)
21+
(mistral-7B-Instruct-v0.3)
22+
and / or
23+
[Llama](https://llama.meta.com/llama-downloads/)
24+
(llama-2-7b-chat or Meta-Llama-3-8B-Instruct)
25+
and / or Gemma2 from [HuggingFace](https://huggingface.co/google/gemma-2-2b-it)
26+
(Gemma-2-2b-it).
27+
- Update `_modelPathMistral`, `_modelPathLlama2`, `_modelPathLlama3`,
28+
`_modelPathGemma2` in the
29+
[LLMExample](../../Tests/GrAIExamples/LLMExample.swift) file with the
30+
previous downloaded weights.
31+
- Optionnally update `_prompt`.
32+
- Rename `_testGenerateMistral`, `_testGenerateLlama2`, `_testGenerateLlama3`
33+
and `_testGenerateGemma2`
34+
into
35+
`testGenerateMistral`, `testGenerateLlama2`, `testGenerateLlama3` and
36+
`testGenerateGemma2`.
37+
- Run the tests.
38+
39+
It is finally possible to clean the environment 🌍
40+
41+
```bash
42+
conda deactivate
43+
conda env remove --name graiexamples
44+
```
45+
46+
## Steps
47+
48+
1. Generate text from a prompt with Mistral 7B Instruct model.
49+
1. Generate text from a prompt with Llama 2 7B Chat model.
50+
1. Generate text from a prompt with Llama 3 8B Instruct model.
51+
1. Generata text from a prompt with Gemme 2 2B Instruct model.
52+
53+
## Further tests
54+
55+
Further tests are available at
56+
[LLMExampleTests](../../Tests/GrAIExamples/LLMExampleTests.swift).
57+
In order to run them, rename
58+
`_testPredict1` and `_testPredict32` into `testPredict1` and `testPredict32`.
59+
60+
The test `testPredict1` compares the first step of generation
61+
of a toy LLM (just one transformer block) in GrAIdient and in PyTorch.
62+
63+
The test `testPredict32` runs the first step of generation
64+
of a full LLM in GrAIdient and compares the expected result from PyTorch.

Docs/Examples/VGG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,17 @@ conda env remove --name graiexamples
9191
1. Train a model on the training dataset.
9292
1. Evaluate the trained model on the testing dataset:
9393
watch a better performance.
94+
95+
## Benchmarks
96+
97+
To benchmark the time performance of the VGG model, look at
98+
[VGGBenchmark](../../Tests/GrAIExamples/VGGBenchmark.swift) and rename
99+
`_test_TrainVGG` and `_test_EvalVGG` into `test_TrainVGG` and `test_EvalVGG`.
100+
101+
The test `test_TrainVGG` will measure the time spent for training the VGG
102+
model for 20 steps.
103+
104+
The test `test_EvalVGG` will measure the time spent for running the VGG model
105+
in inference for 20 steps.
106+
107+
Note that for both tests, the data is random and fixed once and for all.

Docs/Examples/VisionTransformer.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,20 @@ conda env remove --name graiexamples
8686

8787
1. Dump the training dataset.
8888
1. Train a simple Vision Transformer model.
89+
90+
## Benchmarks
91+
92+
To benchmark the time performance of the Vision Transformer model,
93+
look at
94+
[TransformerBenchmark](../../Tests/GrAIExamples/TransformerBenchmark.swift)
95+
and rename
96+
`_test_TrainTransformer` and `_test_EvalTransformer` into
97+
`test_TrainTransformer` and `test_EvalTransformer`.
98+
99+
The test `test_TrainTransformer` will measure the time spent for training the
100+
VisionTransformer model for 20 steps.
101+
102+
The test `test_EvalTransformer` will measure the time spent for running the
103+
VisionTransformer model in inference for 20 steps.
104+
105+
Note that for both tests, the data is random and fixed once and for all.

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import PackageDescription
77
let package = Package(
88
name: "GrAIdient",
99
platforms: [
10-
.macOS(.v10_15)
10+
.macOS(.v13)
1111
],
1212
products: [
1313
.library(

Sources/GrAITestsUtils/Trainer.swift

Lines changed: 153 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ extension TestError: CustomStringConvertible
6969
///
7070
/// - Parameter model: The model on which to select the initialization scheme.
7171
///
72-
func randomSelectWeightsInitializationScheme(model: Model)
72+
public func randomSelectWeightsInitializationScheme(model: Model)
7373
{
7474
let choice = Int.random(in: 0...4)
7575
switch choice {
@@ -365,6 +365,153 @@ open class FlowTrainer: Trainer
365365
}
366366
}
367367

368+
/// Pipeline that compares gradients of weights computed in the CPU execution context againt the GPU one.
369+
open class FlowPrecisionTrainer: Trainer
370+
{
371+
///
372+
/// The two models:
373+
/// [model to execute with Float precision, same model to execute with Float16 precision].
374+
///
375+
public var models: [Model] = []
376+
377+
/// Get the model to execute with Float precision.
378+
public var modelFloat: Model
379+
{
380+
get {
381+
return models[0]
382+
}
383+
}
384+
/// Get the model to execute with Float16 precision.
385+
public var modelFloat16: Model
386+
{
387+
get {
388+
return models[1]
389+
}
390+
}
391+
392+
///
393+
/// Create a model in the two execution contexts: CPU and GPU.
394+
///
395+
/// - Parameter buildFct: A Function that creates the different layers of the models.
396+
///
397+
public func build(_ buildFct: (ModelContext)->())
398+
{
399+
var baseModels = [BaseModel]()
400+
401+
let context = ModelContext(name: modelName + "Float", curID: 0)
402+
buildFct(context)
403+
baseModels.append(context.model)
404+
405+
context.model = BaseModel(name: modelName + "Float16")
406+
buildFct(context)
407+
baseModels.append(context.model)
408+
409+
var models = [Model]()
410+
for baseModel in baseModels
411+
{
412+
models.append(Model(model: baseModel, modelsPrev: []))
413+
}
414+
self.models = models
415+
}
416+
417+
/// Initialize the kernel of the models.
418+
public func initialize()
419+
{
420+
for i in 0...1
421+
{
422+
if i == 0
423+
{
424+
GrAI.Precision.float = true
425+
randomSelectWeightsInitializationScheme(model: modelFloat)
426+
}
427+
428+
if i > 0
429+
{
430+
models[i].weights = models[i-1].weights
431+
}
432+
433+
if i == 1
434+
{
435+
GrAI.Precision.float16 = true
436+
}
437+
438+
models[i].initialize(
439+
params: optimizerParams,
440+
phase: .Training,
441+
deviceID: DEVICE_ID
442+
)
443+
}
444+
}
445+
446+
///
447+
/// Run the test.
448+
///
449+
/// The goal is to compare the gradients of weights computed with Float precision with
450+
/// the gradients of weights computed with Float16 precision.
451+
///
452+
/// - Parameters:
453+
/// - setData: A function to create/set data to the model.
454+
/// - setLoss: A function to create/set ground truth to the model.
455+
/// - validate: A function that checks whether the relative difference is small enough.
456+
///
457+
public func run<DataT, LossT>(
458+
setData: (DataT?, Model)->(DataT, Int),
459+
setLoss: (LossT?, Model)->(LossT),
460+
validate: (Double) throws -> ()) throws
461+
{
462+
initialize()
463+
464+
var epoch = 0
465+
let nbEpochsMax = 1
466+
while epoch < nbEpochsMax
467+
{
468+
var numLoop = 0
469+
while numLoop < optimizerParams.nbLoops
470+
{
471+
let resultsFloat: [Double]
472+
GrAI.Precision.float = true
473+
474+
var (inputs, batchSize) = setData(nil, modelFloat)
475+
modelFloat.updateKernel(batchSize: batchSize)
476+
try! modelFloat.forward()
477+
478+
var gt = setLoss(nil, modelFloat)
479+
try! modelFloat.backward()
480+
try! modelFloat.update()
481+
482+
resultsFloat = getGradients(model: modelFloat)
483+
484+
let resultsFloat16: [Double]
485+
GrAI.Precision.float16 = true
486+
487+
(inputs, batchSize) = setData(inputs, modelFloat16)
488+
modelFloat16.updateKernel(batchSize: batchSize)
489+
try! modelFloat16.forward()
490+
491+
gt = setLoss(gt, modelFloat16)
492+
try! modelFloat16.backward()
493+
try! modelFloat16.update()
494+
495+
resultsFloat16 = getGradients(model: modelFloat16)
496+
497+
if let gradDiff = checkFlow(resultsFloat, resultsFloat16)
498+
{
499+
if gradDiff.isNaN
500+
{
501+
fatalError("NaN")
502+
}
503+
try validate(gradDiff)
504+
}
505+
506+
modelFloat.incStep()
507+
modelFloat16.incStep()
508+
numLoop += 1
509+
}
510+
epoch += 1
511+
}
512+
}
513+
}
514+
368515
/// Compares gradients of weights computed in the CPU execution context againt the GPU one
369516
/// after a call to the reset API.
370517
open class FlowResetTrainer: FlowTrainer
@@ -831,18 +978,18 @@ open class TransformTrainer: FlowTrainer
831978
// 5. Compare results.
832979

833980
let diffCPU =
834-
(lossCPUNew - lossCPURef) * (lossCPUNew - lossCPURef) /
835-
(lossCPUNew * lossCPUNew + lossCPURef * lossCPURef)
981+
(lossCPUNew - lossCPURef) * (lossCPUNew - lossCPURef) /
982+
(lossCPUNew * lossCPUNew + lossCPURef * lossCPURef)
836983
let diffGPU =
837-
(lossGPUNew - lossGPURef) * (lossGPUNew - lossGPURef) /
838-
(lossGPUNew * lossGPUNew + lossGPURef * lossGPURef)
984+
(lossGPUNew - lossGPURef) * (lossGPUNew - lossGPURef) /
985+
(lossGPUNew * lossGPUNew + lossGPURef * lossGPURef)
839986

840987
var warning = ""
841988
let maxDiff = max(diffCPU, diffGPU)
842989
let maxIndex = diffCPU < diffGPU ? "GPU" : "CPU"
843990
if diffCPU > 0.0000001
844991
{
845-
warning = "Load Check Warning " + maxIndex + " : "
992+
warning = "Transform Check Warning " + maxIndex + " : "
846993
}
847994
let strDump = warning + String(maxDiff)
848995
print(strDump)

0 commit comments

Comments
 (0)