KI-gestütztes Programmieren mit CodeGemma und KerasNLP

Auf ai.google.dev ansehen In Google Colab ausführen Quelle auf GitHub ansehen

Übersicht

CodeGemma ist eine Variante von Gemma, die auf Programmieraufgaben zugeschnitten ist. Dieses Tutorial baut auf dem Keras CodeGemma-Schnellstart auf und zeigt Ihnen weitere Möglichkeiten, wie CodeGemma Ihre Programmieraufgaben unterstützen kann.

Einrichtung

Zugriff auf CodeGemma erhalten

Um diese Anleitung abzuschließen, müssen Sie zuerst die Schritte unter Gemma-Einrichtung ausführen. In der Anleitung zur Einrichtung von Gemma erfahren Sie, wie Sie Folgendes tun können:

  • Auf kaggle.com erhalten Sie Zugriff auf Gemma.
  • Wählen Sie eine Colab-Laufzeit mit ausreichenden Ressourcen zum Ausführen des Gemma 7B-Modells aus.
  • Generieren und konfigurieren Sie einen Kaggle-Nutzernamen und einen API-Schlüssel.

Nachdem Sie die Gemma-Einrichtung abgeschlossen haben, fahren Sie mit dem nächsten Abschnitt fort. Dort legen Sie Umgebungsvariablen für Ihre Colab-Umgebung fest.

Laufzeit auswählen

Zum Ausführen der CodeGemma 7B-Modelle benötigen Sie ein kostenpflichtiges Colab Pro-Abo, das eine Laufzeit mit A100-GPU bietet.

  1. Wählen Sie rechts oben im Colab-Fenster ▾ aus (Zusätzliche Verbindungsoptionen).
  2. Wählen Sie Laufzeittyp ändern aus.
  3. Wählen Sie unter Hardwarebeschleuniger die Option A100 GPU aus.

API-Schlüssel konfigurieren

Um Gemma zu verwenden, müssen Sie Ihren Kaggle-Nutzernamen und einen Kaggle API-Schlüssel angeben.

Um einen Kaggle-API-Schlüssel zu generieren, gehen Sie in Ihrem Kaggle-Nutzerprofil zum Tab Account (Konto) und wählen Sie Create New Token (Neues Token erstellen) aus. Dadurch wird der Download einer kaggle.json-Datei mit Ihren API-Anmeldedaten ausgelöst.

Wählen Sie in Colab im linken Bereich Secrets (🚀) aus und fügen Sie Ihren Kaggle-Nutzernamen und Ihren Kaggle API-Schlüssel hinzu. Speichern Sie Ihren Nutzernamen unter dem Namen KAGGLE_USERNAME und Ihren API-Schlüssel unter dem Namen KAGGLE_KEY.

Umgebungsvariablen festlegen

Legen Sie Umgebungsvariablen für KAGGLE_USERNAME und KAGGLE_KEY fest.

import os
from google.colab import userdata

os.environ["KAGGLE_USERNAME"] = userdata.get('KAGGLE_USERNAME')
os.environ["KAGGLE_KEY"] = userdata.get('KAGGLE_KEY')

Abhängigkeiten installieren

pip install -q -U keras-nlp

Backend auswählen

Keras ist eine Deep-Learning-API mit mehreren Frameworks, die auf einfache und nutzerfreundliche Weise entwickelt wurde. Mit Keras 3 können Sie Workflows auf einem von drei Back-Ends ausführen: TensorFlow, JAX oder PyTorch.

Konfigurieren Sie für diese Anleitung das Back-End für JAX.

os.environ["KERAS_BACKEND"] = "jax"  # Or "tensorflow" or "torch".

Pakete importieren

Importieren Sie Keras und KerasNLP.

import keras_nlp
import keras

# Run at half precision.
keras.config.set_floatx("bfloat16")

CodeGemma 7B-Modellbeispiele

Dieser Abschnitt enthält Beispiele für die Verwendung des vortrainierten 7B-CodeGemma-Modells zur Unterstützung bei Programmieraufgaben.

Modell laden

KerasNLP bietet Implementierungen aller drei CodeGemma-Varianten (2B und 7B vortrainiert (PT) und 7B Instruction-tuned (IT)) mithilfe von GemmaCausalLM, einem End-to-End-Gemma-Modell für kausale Sprachmodelle. Ein kausales Sprachmodell sagt das nächste Token basierend auf vorherigen Tokens voraus.

In diesem Beispiel wird das Modell code_gemma_7b_en mit der Methode from_preset geladen.

gemma_lm_7b = keras_nlp.models.GemmaCausalLM.from_preset("code_gemma_7b_en")
Downloading from https://www.kaggle.com/api/v1/models/keras/codegemma/keras/code_gemma_7b_en/1/download/config.json...
100%|██████████| 556/556 [00:00<00:00, 790kB/s]
Downloading from https://www.kaggle.com/api/v1/models/keras/codegemma/keras/code_gemma_7b_en/1/download/model.weights.h5...
100%|██████████| 15.9G/15.9G [02:39<00:00, 107MB/s]
Downloading from https://www.kaggle.com/api/v1/models/keras/codegemma/keras/code_gemma_7b_en/1/download/tokenizer.json...
100%|██████████| 401/401 [00:00<00:00, 587kB/s]
Downloading from https://www.kaggle.com/api/v1/models/keras/codegemma/keras/code_gemma_7b_en/1/download/assets/tokenizer/vocabulary.spm...
100%|██████████| 4.04M/4.04M [00:00<00:00, 16.4MB/s]
gemma_lm_7b.summary()

Die Methode from_preset instanziiert das Modell aus einer voreingestellten Architektur und Gewichtungen.

Codevervollständigung mit mehrzeiligem FIM

Die PT CodeGemma-Modelle werden mit Aufgaben zur Code-Füllung trainiert. Dieser Abschnitt zeigt Beispiele, in denen die mehrzeilige FIM-Funktion von CodeGemma verwendet wird, um Code an der angegebenen Cursorposition basierend auf dem umgebenden Kontext automatisch auszufüllen.

Definieren Sie zunächst Konstanten und eine Hilfsfunktion für die Prompt-Formatierung.

# Formatting control tokens to specify cursor location
BEFORE_CURSOR = "<|fim_prefix|>"
AFTER_CURSOR = "<|fim_suffix|>"
AT_CURSOR = "<|fim_middle|>"
FILE_SEPARATOR = "<|file_separator|>"

# Define model stop tokens
END_TOKEN = gemma_lm_7b.preprocessor.tokenizer.end_token
stop_tokens = (BEFORE_CURSOR, AFTER_CURSOR, AT_CURSOR, FILE_SEPARATOR, END_TOKEN)
stop_token_ids = tuple(gemma_lm_7b.preprocessor.tokenizer.token_to_id(x) for x in stop_tokens)

def format_completion_prompt(before, after):
    return f"{BEFORE_CURSOR}{before}{AFTER_CURSOR}{after}{AT_CURSOR}"

Beispiel 1 – Fehlende Bedingung einfügen

Der Beispielcode unten zum Generieren der Fibonacci-Sequenz wird in folgenden Fällen nicht korrekt ausgeführt:n=1:

def fibonacci(n: int) -> int:
  if n == 0:
    return 0
  # The cursor is right before the e in the following line
  else:
    return fibonacci(n - 1) + fibonacci(n - 2)

Wenn sich der Cursor am Anfang der Zeile 4 befindet (wobei sich die else-Klausel befindet), sieht der Inhalt vor und nach dem Cursor so aus:

before = """def fibonacci(n: int) -> int:\n  if n == 0:\n    return 0\n""" # Mind the spaces!
after = """\n  else:\n    return fibonacci(n - 1) + fibonacci(n-2)\n"""
prompt = format_completion_prompt(before, after)
print(prompt)
<|fim_prefix|>def fibonacci(n: int) -> int:
  if n == 0:
    return 0
<|fim_suffix|>
  else:
    return fibonacci(n - 1) + fibonacci(n-2)
<|fim_middle|>

Führen Sie die Aufforderung aus.

print(gemma_lm_7b.generate(prompt, stop_token_ids=stop_token_ids, max_length=128))
<|fim_prefix|>def fibonacci(n: int) -> int:
  if n == 0:
    return 0
<|fim_suffix|>
  else:
    return fibonacci(n - 1) + fibonacci(n-2)
<|fim_middle|>elif n == 1:
    return 1<|file_separator|>

Das Modell fügt die korrekte elif-Konfiguration für n=1 an der Position des Cursors ein.

Beispiel 2: Vollständiger DFS-Durchlaufalgorithmus

Code zur automatischen Vervollständigung für einen DFS-Strukturdurchlaufalgorithmus (Deep-First Search).

before = """void dfs(node* root) {
  if (root->left) {
    dfs(root->left);
  }"""
after = """\nprintf("%d", root->value);
}"""
prompt = format_completion_prompt(before, after)
print(prompt)
<|fim_prefix|>void dfs(node* root) {
  if (root->left) {
    dfs(root->left);
  }<|fim_suffix|>
printf("%d", root->value);
}<|fim_middle|>

Führen Sie die Aufforderung aus.

print(gemma_lm_7b.generate(prompt, stop_token_ids=stop_token_ids, max_length=128))
<|fim_prefix|>void dfs(node* root) {
  if (root->left) {
    dfs(root->left);
  }<|fim_suffix|>
printf("%d", root->value);
}<|fim_middle|>
  if (root->right) {
    dfs(root->right);
  }<|file_separator|>

Codegenerierung

CodeGemma 7B PT kann nicht nur Code einfügen, sondern auch mit Natural Language-Korpus trainiert werden. Damit können Sie das Modell auffordern, Code zu generieren.

generation_prompt= """Write a rust function to identify non-prime numbers.
Examples:
>>> is_not_prime(2)
False
>>> is_not_prime(10)
True
pub fn is_not_prime(n: i32) -> bool {"""
print(gemma_lm_7b.generate(generation_prompt, max_length=500))
Write a rust function to identify non-prime numbers.
Examples:
>>> is_not_prime(2)
False
>>> is_not_prime(10)
True
pub fn is_not_prime(n: i32) -> bool {
    if n <= 1 {
        return true;
    }
    for i in 2..n {
        if n % i == 0 {
            return true;
        }
    }
    false
}

7 Mrd. IT-Modellbeispiele

In diesem Abschnitt wird das CodeGemma 7B Instruction-Tuned-Modell für fortgeschrittene Programmieraufgaben verwendet. Das IT-Modell von CodeGemma 7B wurde vom CodeGemma 7B PT-Modell durch überwachte Abstimmung des Codes und bestärkendes Lernen mit menschlichem Feedback abgeleitet. In diesem Abschnitt finden Sie Beispiele für die Verwendung dieses Modells für die offene Generierung.

IT-Modell laden

Laden Sie das Modell code_gemma_instruct_7b_en mit der Methode from_preset.

gemma_lm_7b_it = keras_nlp.models.GemmaCausalLM.from_preset("code_gemma_instruct_7b_en")
gemma_lm_7b_it.summary()
Downloading from https://www.kaggle.com/api/v1/models/keras/codegemma/keras/code_gemma_instruct_7b_en/1/download/config.json...
100%|██████████| 556/556 [00:00<00:00, 754kB/s]
Downloading from https://www.kaggle.com/api/v1/models/keras/codegemma/keras/code_gemma_instruct_7b_en/1/download/model.weights.h5...
100%|██████████| 15.9G/15.9G [03:18<00:00, 86.2MB/s]
Downloading from https://www.kaggle.com/api/v1/models/keras/codegemma/keras/code_gemma_instruct_7b_en/1/download/tokenizer.json...
100%|██████████| 401/401 [00:00<00:00, 593kB/s]
Downloading from https://www.kaggle.com/api/v1/models/keras/codegemma/keras/code_gemma_instruct_7b_en/1/download/assets/tokenizer/vocabulary.spm...
100%|██████████| 4.04M/4.04M [00:00<00:00, 16.8MB/s]

IT-Modelle werden mit einem bestimmten Formatierer trainiert, der alle Beispiele zur Feinabstimmung von Anweisungen mit zusätzlichen Informationen versieht, um Rollen anzugeben und Wendungen in einer Unterhaltung abzugrenzen.

Definieren Sie zunächst Konstanten und eine Hilfsfunktion für die Prompt-Formatierung.

# Formatting control tokens for instruction tuning
START_OF_TURN_USER = "<start_of_turn>user"
END_OF_TURN = "<end_of_turn>"
START_OF_TURN_MODEL = "<start_of_turn>model"

# Formatting helper function
def format_instruction_prompt(context):
    return f"{START_OF_TURN_USER}\n{context}{END_OF_TURN}\n{START_OF_TURN_MODEL}\n"

Codeübersetzung

context1 = """
You are an experienced C and Python programmer. Convert the following Python code into C.
```python
def factorial(n):
    result = 1
    for i in range(2, n + 1):
        result *= i
    return result
```\n"""

Formatieren Sie den Prompt.

prompt1 = format_instruction_prompt(context1)
print(prompt1)
<start_of_turn>user

You are an experienced C and Python programmer. Convert the following Python code into C.

```python
def factorial(n):
    result = 1
    for i in range(2, n + 1):
        result *= i
    return result
```
<end_of_turn>
<start_of_turn>model

Führen Sie die Aufforderung aus.

print(gemma_lm_7b_it.generate(prompt1, max_length=500))
<start_of_turn>user

You are an experienced C and Python programmer. Convert the following Python code into C.

```python
def factorial(n):
    result = 1
    for i in range(2, n + 1):
        result *= i
    return result
```
<end_of_turn>
<start_of_turn>model
Here is the C code equivalent of the Python code:

```c
int factorial(int n) {
  int result = 1;
  for (int i = 2; i <= n; i++) {
    result *= i;
  }
  return result;
}
```

Here is a breakdown of the changes:

* The function is declared with the `int` return type, as in Python.
* The `for` loop is converted to a `for` loop with an `int` variable `i` initialized to 2 and incremented by 1 in each iteration.
* The `range` function is replaced with a simple loop that iterates from 2 to `n` (inclusive).
* The `result *= i` statement is used to multiply `result` by `i` in each iteration.
* The `return` statement is used to return the final value of `result`.

Erkennung von Code-Sicherheitslücken

context2 = """
You are an experienced C++ programmer hunting for vulnerable code. Is the following code vulnerable? Explain your reasoning.
```cpp
int i;
unsigned int numWidgets;
Widget **WidgetList;

numWidgets = GetUntrustedSizeValue();
if ((numWidgets == 0) || (numWidgets > MAX_NUM_WIDGETS)) {
    ExitError("Incorrect number of widgets requested!");
}
WidgetList = (Widget **) malloc(numWidgets * sizeof(Widget *));
printf("WidgetList ptr=%p\n", WidgetList);
for (i = 0; i < numWidgets; i++) {
    WidgetList[i] = InitializeWidget();
}
WidgetList[numWidgets] = NULL;
showWidgets(WidgetList);
```\n"""

Formatieren Sie den Prompt.

prompt2 = format_instruction_prompt(context2)
print(prompt2)
<start_of_turn>user

You are an experienced C++ programmer hunting for vulnerable code. Is the following code vulnerable? Explain your reasoning.

```cpp
int i;
unsigned int numWidgets;
Widget **WidgetList;

numWidgets = GetUntrustedSizeValue();
if ((numWidgets == 0) || (numWidgets > MAX_NUM_WIDGETS)) {
    ExitError("Incorrect number of widgets requested!");
}
WidgetList = (Widget **) malloc(numWidgets * sizeof(Widget *));
printf("WidgetList ptr=%p
", WidgetList);
for (i = 0; i < numWidgets; i++) {
    WidgetList[i] = InitializeWidget();
}
WidgetList[numWidgets] = NULL;
showWidgets(WidgetList);
```
<end_of_turn>
<start_of_turn>model
print(gemma_lm_7b_it.generate(prompt2, max_length=1000))
<start_of_turn>user

You are an experienced C++ programmer hunting for vulnerable code. Is the following code vulnerable? Explain your reasoning.

```cpp
int i;
unsigned int numWidgets;
Widget **WidgetList;

numWidgets = GetUntrustedSizeValue();
if ((numWidgets == 0) || (numWidgets > MAX_NUM_WIDGETS)) {
    ExitError("Incorrect number of widgets requested!");
}
WidgetList = (Widget **) malloc(numWidgets * sizeof(Widget *));
printf("WidgetList ptr=%p
", WidgetList);
for (i = 0; i < numWidgets; i++) {
    WidgetList[i] = InitializeWidget();
}
WidgetList[numWidgets] = NULL;
showWidgets(WidgetList);
```
<end_of_turn>
<start_of_turn>model
Yes, the code is vulnerable to a memory access error.

**Reasoning:**

* The code allocates memory for `WidgetList` using `malloc` based on the value of `numWidgets`.
* However, the loop iterates from `0` to `numWidgets`, which is one element beyond the allocated memory.
* This means that accessing `WidgetList[numWidgets]` will result in a memory access error, as it is outside the bounds of the allocated memory.

**Example of Memory Access Error:**

When `numWidgets` is 5, the code allocates memory for `WidgetList` as follows:

```
WidgetList = (Widget **) malloc(5 * sizeof(Widget *));
```

The loop iterates from 0 to 4, accessing the following elements:

* `WidgetList[0]`
* `WidgetList[1]`
* `WidgetList[2]`
* `WidgetList[3]`
* `WidgetList[4]`

However, the code then attempts to access `WidgetList[5]`, which is outside the allocated memory range. This will result in a memory access error.

**Solution:**

To resolve this vulnerability, the loop should be modified to iterate from 0 to `numWidgets - 1`:

```cpp
for (i = 0; i < numWidgets - 1; i++) {
    WidgetList[i] = InitializeWidget();
}
```

This ensures that the loop does not access elements beyond the allocated memory range.

Das Modell erkennt eine potenzielle Sicherheitslücke im Code und bietet Codeänderungen zur Behebung an.

Zusammenfassung

In dieser Anleitung wurden Sie durch die Verwendung von CodeGemma für eine Vielzahl von Programmieraufgaben geführt. Weitere Informationen zu CodeGemma: