1
1

IBM の Granite Code Models を Google Colaboratory で動かす

Last updated at Posted at 2024-07-19

はじめに

IBM 社が OSS として公開した「コード生成LLM」である Granite-8B-Code-Base を Google Colaboratory 上で動かします

GitHub Copilot のように、プログラムコードを生成してくれるモデルです

基本的には以前他社のモデルで実行したのと同じ手法になります

モデルの種類は以下の通り

  • ibm-granite/granite-3b-code-base
  • ibm-granite/granite-3b-code-instruct
  • ibm-granite/granite-8b-code-base
  • ibm-granite/granite-8b-code-instruct
  • ibm-granite/granite-20b-code-base
  • ibm-granite/granite-20b-code-instruct
  • ibm-granite/granite-34b-code-base
  • ibm-granite/granite-34b-code-instruct

-base はコードの補完、 -instruct は指示によるコード生成を行います

また、 b = 10億パラメーター を表します

-3b- だと 30 億、 -8b- だと 80 億です

この記事では 3b と 8b のモデルを使います

モデルの取得元

モデルは商用利用可能なライセンスで HuggingFace 上に公開されています

モデルのダウンロードに Hugguing Face のアクセストークンが必要になるので、サインアップしてトークンを用意しておきましょう

設定画面の左メニューから「Access Tokens」を開き、「New token」ボタンでトークンが作成できます

トークン取得

Google Colab のランタイム

Google Colab の GPU ランタイムは3つ存在します

それぞれ VRAM の容量に違いがあります

  • T4: 15 GB
  • L4: 22.5 GB
  • A100: 40 GB

3b や 8b などのパラメーター数が多くなればメモリの容量も多く必要になるため、それに応じたランタイムを選択しましょう

メモリが不足している場合はモデルのロード中に以下の警告メッセージが表示されます

CPU で動かそうとするため推論が極端に遅くなります(実質使用不可能です)

WARNING:accelerate.big_modeling:Some parameters are on the meta device device because they were offloaded to the cpu.

今回扱うモデルの場合、以下に示す容量が必要です

  • 3b: 6.4 GB = T4 で実行可能
  • 8b: 15.4 GB = L4 で実行可能

T4 は無償版で利用可能ですが、 L4 や A100 が必要な場合は有償契約しましょう

共通手順

どのモデルを使用する場合も共通の手順です

ノートブックの設定

新しいノートブックを開きます

上メニューから「ランタイム」 |> 「ランタイムのタイプを変更」を開きます

スクリーンショット 2024-03-22 17.34.25.png

ハードウェアアクセラレータで利用する GPU を選択し、「保存」をクリックします
(3b の場合は T4 GPU 、 8b の場合は L4 GPU)

スクリーンショット 2024-07-07 20.06.51.png

左メニューの鍵アイコンをクリックし、 HF_TOKEN という名前で Hugging Face のアクセストークンをシークレットに登録しておきます

「ノートブックからのアクセス」を忘れず ON にしておきましょう

スクリーンショット 2024-03-24 12.36.55.png

セットアップ

以降、 Colab のセルにコードを貼り付けて実行します

pip 自体を最新化してから、必要なモジュールをインストールします

!pip install --upgrade pip
!pip install --upgrade accelerate transformers gradio

モジュールをインポートしておきます

import gradio as gr
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

gradio は最後に UI を作るためのものなので、モデルを動かしたいだけの場合は不要です

モデルのロード

transformers の機能で Hugging Face からトークナイザー、モデルをダウンロードし、ロードします

model_name には利用するモデル名(HuggingFace 上の ID)を指定します

device_map="auto" を指定することで、自動的に環境に合った状態(GPU の有無など)でロードしてくれます

model_name = "ibm-granite/granite-8b-code-base"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype="auto",
    device_map="auto",
)
model.eval()

ロードすると GPU の使用率が上がります

スクリーンショット 2024-07-18 14.04.39.png

コード補完

-base が末尾につくモデルを使用し、途中まで書いたコードを補完します

モデルによるコード補完の実行

input_text = "def max(a, b, c):"
input_tokens = tokenizer(input_text, return_tensors="pt")
for i in input_tokens:
    input_tokens[i] = input_tokens[i].to(model.device)

with torch.no_grad():
    output_tokens = model.generate(**input_tokens, max_new_tokens=1024)

output = tokenizer.batch_decode(output_tokens, skip_special_tokens=True)

for i in output:
    print(i)

granite-3b-code-base の場合、実行結果は以下のように出力されます

def max(a, b, c):
    if a > b:
        if a > c:
            return a
        else:
            return c
    else:
        if b > c:
            return b
        else:
            return c

def min(a, b, c):
    if a < b:
        if a < c:
            return a
        else:
            return c
    else:
        if b < c:
            return b
        else:
            return c

def main():
    n = int(input())
    a = list(map(int, input().split()))
    b = list(map(int, input().split()))
    c = list(map(int, input().split()))
    a.sort()
    b.sort()
    c.sort()
    print(max(a[0] + b[1] + c[2], a[1] + b[2] + c[0], a[2] + b[0] + c[1]))

if __name__ == '__main__':
    main()

3b なので微妙な結果ですが、意図は汲んでくれています

UI付きで実行

Gradio を使って簡易的な UI を用意します

まず、入力を出力に変換するための関数を用意します

def chat(input_text):
    input_tokens = tokenizer(input_text, return_tensors="pt")
    for i in input_tokens:
        input_tokens[i] = input_tokens[i].to(model.device)

    with torch.no_grad():
        output_tokens = model.generate(**input_tokens, max_new_tokens=1024)

    output = tokenizer.batch_decode(output_tokens, skip_special_tokens=True)

    return output[0]

Gradio で入出力を定義します

gr.Interface(
    fn=chat,
    inputs=[gr.Textbox()],
    outputs=[gr.Textbox()]
).launch(debug=True)

実行すると、以下のような UI が表示されます

スクリーンショット 2024-03-22 17.48.19.png

左側の input にコードの最初の部分を入力してみます

「Submit」を押すと、右側の output に生成結果が表示されます

スクリーンショット 2024-07-18 14.09.39.png

コード補完の問答集

Python 距離計算

入力

def distance(point1, point2):

3b の出力

距離計算は正しいですが、その後に続く関数は実用的に思えません

def distance(point1, point2):
    return math.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2)


def get_angle(point1, point2, point3):
    return math.degrees(math.atan2(point2[1] - point1[1], point2[0] - point1[0]) - math.atan2(point3[1] - point1[1], point3[0] - point1[0]))


def get_angle_between_points(point1, point2):
    return math.degrees(math.atan2(point2[1] - point1[1], point2[0] - point1[0]))


def get_angle_between_points_and_x_axis(point1, point2):
    return math.degrees(math.atan2(point2[1] - point1[1], point2[0] - point1[0]))


def get_angle_between_points_and_y_axis(point1, point2):
    return math.degrees(math.atan2(point2[0] - point1[0], point2[1] - point1[1]))


def get_angle_between_points_and_z_axis(point1, point2):
    return math.degrees(math.atan2(point2[2] - point1[2], point2[1] - point1[1]))


def get_angle_between_points_and_xy_plane(point1, point2):
    return math.degrees(math.atan2(point2[2] - point1[2], point2[0] - point1[0]))


def get_angle_between_points_and_xz_plane(point1, point2):
    return math.degrees(math.atan2(point2[1] - point1[1], point2[0] - point1[0]))


def get_angle_between_points_and_yz_plane(point1, point2):
    return math.degrees(math.atan2(point2[0] - point1[0], point2[2] - point1[2]))


def get_angle_between_points_and_xyz_plane(point1, point2):
    return math.degrees(math.atan2(point2[2] - point1[2], point2[1] - point1[1]))


def get_angle_between_points_and_xy_plane_and_z_axis(point1, point2):
    return math.degrees(math.atan2(point2[1] - point1[1], point2[0] - point1[0]))


def get_angle_between_points_and_xz_plane_and_y_axis(point1, point2):
    return math.degrees(math.atan2(point2[0] - point1[0], point2[2] - point1[2]))


def get_angle_between_points_and_yz_plane_and_x_axis(point1, point2):
    return math.degrees(math.atan2(point2[2] - point1[2], point2[1] - point1[1]))


def get_angle_between_points_and_xyz_plane_and_xy_plane(point1, point2):
    return math.degrees(math.atan2(point2[1] - point1[1], point2[0] - point1[0]))


def get_angle_between_points_and_xyz_plane_and_xz_plane(point1, point2):
    return math.degrees(math.atan2(point2[0] - point1[0], point2[2] - point1[2]))


def get_angle_between_points_and_xyz_plane_and_yz_plane(point1, point2):
    return math.degrees(math.atan2(point2[2] - point1[2], point2[1] - point1[1]))


def get_angle_between_points_and_xyz_plane_and_xyz_plane(point1, point2):
    return math.degrees(math.atan2(point2[1] - point1[1], point2[0] - point1[0]))


def get_angle_between_points_and_xy_plane_and_xy_plane(point1, point2):
    return math.degrees

8b の出力

距離の計算以外の関数が実用的なものになっている感じがします

def distance(point1, point2):
    return math.sqrt((point1[0] - point2[0])**2 + (point1[1] - point2[1])**2)

# Function to calculate the angle between two vectors
def angle_between(v1, v2):
    return math.acos(np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2)))

# Function to calculate the area of the triangle
def triangle_area(a, b, c):
    s = (a + b + c) / 2
    return math.sqrt(s * (s - a) * (s - b) * (s - c))

# Function to calculate the area of the polygon
def polygon_area(points):
    area = 0.0
    for i in range(len(points)):
        j = (i + 1) % len(points)
        area += points[i][0] * points[j][1]
        area -= points[j][0] * points[i][1]
    area = abs(area) / 2.0
    return area

# Function to calculate the perimeter of the polygon
def polygon_perimeter(points):
    perimeter = 0.0
    for i in range(len(points)):
        j = (i + 1) % len(points)
        perimeter += distance(points[i], points[j])
    return perimeter

# Function to calculate the centroid of the polygon
def polygon_centroid(points):
    x_sum = 0.0
    y_sum = 0.0
    for i in range(len(points)):
        x_sum += points[i][0]
        y_sum += points[i][1]
    centroid = (x_sum / len(points), y_sum / len(points))
    return centroid

# Function to calculate the inradius of the polygon
def polygon_inradius(points):
    area = polygon_area(points)
    perimeter = polygon_perimeter(points)
    inradius = area / perimeter
    return inradius

# Function to calculate the circumradius of the polygon
def polygon_circumradius(points):
    centroid = polygon_centroid(points)
    distances = [distance(centroid, point) for point in points]
    circumradius = max(distances)
    return circumradius

# Function to calculate the regularity of the polygon
def polygon_regularity(points):
    centroid = polygon_centroid(points)
    distances = [distance(centroid, point) for point in points]
    regularity = max(distances) / min(distances)
    return regularity

# Function to calculate the number of sides of the polygon
def polygon_num_sides(points):
    return len(points)

# Function to calculate the number of vertices of the polygon
def polygon_num_vertices(points):
    return len(points)

# Function to calculate the number of diagonals of the polygon
def polygon_num_diagonals(points):
    num_sides = len(points)
    num_diagonals = num_sides * (num_sides - 3) / 2
    return num_diagonals

# Function to calculate the number of acute angles of the polygon
def polygon_num_acute_angles(points):
    num_acute_angles = 0
    for i in range(len(points)):
        j = (i + 1) % len(points)
        k = (i + 2) % len(points)
        v1 = np.array(points[j]) - np.array(points[i])
        v2 = np.array(points[k]) - np.array(points[i])
        angle = angle_between(v1, v2)
        if angle < math.pi / 2:
            num_acute_angles += 1
    return num_acute_angles

# Function to calculate the number of obtuse angles of the polygon
def polygon_num_obtuse_angles(points):
    num_obtuse_angles = 0
    for i in range(len(points)):
        j = (i + 1) % len(points)
        k = (i + 2) % len(points)
        v1 = np.array(points[j]) - np.array(points[i])
        v2 = np.array(points[k]) - np.array(points[i])
        angle = angle_between(v1, v2)
        if angle > math.pi / 2:
            num_obtuse_angles += 1
    return num_

Python 画像処理(ガンマ補正)

入力

import cv2
import numpy as np

def adjust_gamma(image, gamma=1.0):

3b の出力

ガンマ補正は正しそうですが、意味もなく同じ関数を繰り返しています

import cv2
import numpy as np

def adjust_gamma(image, gamma=1.0):
    # build a lookup table mapping the pixel values [0, 255] to
    # their adjusted gamma values
    invGamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** invGamma) * 255
        for i in np.arange(0, 256)]).astype("uint8")
    # apply gamma correction using the lookup table
    return cv2.LUT(image, table)

def adjust_gamma_image(image, gamma=1.0):
    # build a lookup table mapping the pixel values [0, 255] to
    # their adjusted gamma values
    invGamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** invGamma) * 255
        for i in np.arange(0, 256)]).astype("uint8")
    # apply gamma correction using the lookup table
    return cv2.LUT(image, table)

def adjust_gamma_image_2(image, gamma=1.0):
    # build a lookup table mapping the pixel values [0, 255] to
    # their adjusted gamma values
    invGamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** invGamma) * 255
        for i in np.arange(0, 256)]).astype("uint8")
    # apply gamma correction using the lookup table
    return cv2.LUT(image, table)

def adjust_gamma_image_3(image, gamma=1.0):
    # build a lookup table mapping the pixel values [0, 255] to
    # their adjusted gamma values
    invGamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** invGamma) * 255
        for i in np.arange(0, 256)]).astype("uint8")
    # apply gamma correction using the lookup table
    return cv2.LUT(image, table)

def adjust_gamma_image_4(image, gamma=1.0):
    # build a lookup table mapping the pixel values [0, 255] to
    # their adjusted gamma values
    invGamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** invGamma) * 255
        for i in np.arange(0, 256)]).astype("uint8")
    # apply gamma correction using the lookup table
    return cv2.LUT(image, table)

def adjust_gamma_image_5(image, gamma=1.0):
    # build a lookup table mapping the pixel values [0, 255] to
    # their adjusted gamma values
    invGamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** invGamma) * 255
        for i in np.arange(0, 256)]).astype("uint8")
    # apply gamma correction using the lookup table
    return cv2.LUT(image, table)

def adjust_gamma_image_6(image, gamma=1.0):
    # build a lookup table mapping the pixel values [0, 255] to
    # their adjusted gamma values
    invGamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** invGamma) * 255
        for i in np.arange(0, 256)]).astype("uint8")
    # apply gamma correction using the lookup table
    return cv2.LUT(image, table)

def adjust_gamma_image_7(image, gamma=1.0):
    # build a lookup table mapping the pixel values [0, 255] to
    # their adjusted gamma values
    invGamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** invGamma) * 255
        for i in np.arange(0, 256)]).astype("uint8")
    # apply gamma correction using the lookup table
    return cv2.LUT(image, table)

def adjust_gamma_image_8(image, gamma=1.0):
    # build a lookup table mapping the pixel values [0, 255] to
    # their adjusted gamma values
    invGamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** invGamma) * 

8b の出力

実際に使うところまで生成してくれています

import cv2
import numpy as np

def adjust_gamma(image, gamma=1.0):
    # build a lookup table mapping the pixel values [0, 255] to
    # their adjusted gamma values
    invGamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** invGamma) * 255
        for i in np.arange(0, 256)]).astype("uint8")
 
    # apply gamma correction using the lookup table
    return cv2.LUT(image, table)

def main():
    img = cv2.imread('images/lena.png')
    img = adjust_gamma(img, 0.5)
    cv2.imshow('image', img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

Elixir 平均値取得

入力

defmodule User do
  defstruct name: "", age: 0
end

defmodule UserStats do
  def average_age(users) when is_list(users) do

3b の出力

説明を加えてくれました

defmodule User do
  defstruct name: "", age: 0
end

defmodule UserStats do
  def average_age(users) when is_list(users) do
    Enum.sum(Enum.map(users, & &1.age)) / length(users)
  end
end
```

In this solution, we define a module called `User` with a struct that includes the `name` and `age` fields. We also define a module called `UserStats` with a function `average_age` that takes a list of `User` structs as input and calculates the average age by summing the ages of all users and dividing by the number of users.

8b の出力

モジュールを使うコードまで出力してくれました

defmodule User do
  defstruct name: "", age: 0
end

defmodule UserStats do
  def average_age(users) when is_list(users) do
    total_age = Enum.reduce(users, 0, fn user, acc -> acc + user.age end)
    length(users) / total_age
  end
end

# Example usage
user1 = %User{name: "John", age: 25}
user2 = %User{name: "Jane", age: 30}
users = [user1, user2]

IO.puts("Average age of users: #{UserStats.average_age(users)}")

JavaScript (React)

入力

import React, { useState } from'react';

const Counter = () => {
  // useStateフックを使用してカウントの状態を管理
  const [count, setCount] = useState(0);

  // カウントアップの関数
  const increment = () => {
    setCount(count + 1);
  };

3b の出力

同じ説明を狂ったように繰り返していて怖いです

import React, { useState } from'react';

const Counter = () => {
  // useStateフックを使用してカウントの状態を管理
  const [count, setCount] = useState(0);

  // カウントアップの関数
  const increment = () => {
    setCount(count + 1);
  };

  // カウントダウンの関数
  const decrement = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
};

export default Counter;
```

このコードでは、useStateフックを使用してカウンターの状態を管理しています。useStateフックは、Reactコンポーネントの内部で使用できる、状態と状態の更新を管理するための関数です。useStateフックは、2つの引数を取ります。最初の引数は、状態の初期値です。2番目の引数は、状態を更新するための関数です。

カウンターの状態は、useStateフックの戻り値の配列の最初の要素に格納されます。useStateフックの戻り値の配列の2番目の要素は、状態を更新するための関数です。

カウンターの状態を更新するための関数は、increment関数とdecrement関数です。increment関数は、カウントを1増やす関数です。decrement関数は、カウントを1減らす関数です。

Reactコンポーネントの内部では、setState関数を使用してカウンターの状態を更新できます。setState関数は、Reactコンポーネントの内部で使用できる、状態を更新するための関数です。setState関数は、1つの引数を取ります。最初の引数は、新しい状態です。

setState関数は、Reactコンポーネントの内部で使用できる、状態を更新するための関数です。setState関数は、1つの引数を取ります。最初の引数は、新しい状態です。

setState関数は、Reactコンポーネントの内部で使用できる、状態を更新するための関数です。setState関数は、1つの引数を取ります。最初の引数は、新しい状態です。

setState関数は、Reactコンポーネントの内部で使用できる、状態を更新するための関数です。setState関数は、1つの引数を取ります。最初の引数は、新しい状態です。

setState関数は、Reactコンポーネントの内部で使用できる、状態を更新するための関数です。setState関数は、1つの引数を取ります。最初の引数は、新しい状態です。

setState関数は、Reactコンポーネントの内部で使用できる、状態を更新するための関数です。setState関数は、1つの引数を取ります。最初の引数は、新しい状態です。

setState関数は、Reactコンポーネントの内部で使用できる、状態を更新するための関数です。setState関数は、1つの引数を取ります。最初の引数は、新しい状態です。

setState関数は、Reactコンポーネントの内部で使用できる、状態を更新するための関数です。setState関数は、1つの引数を取ります。最初の引数は、新しい状態です。

setState関数は、Reactコンポーネントの内部で使用できる、状態を更新するための関数です。setState関数は、1つの引数を取ります。最初の引数は、新しい状態です。

setState関数は、Reactコンポーネントの内部で使用できる、状態を更新するための関数です。setState関数は、1つの引数を取ります。最初の引数は、新しい状態です。

setState関数は、Reactコンポーネントの内部で使用できる、状態を更新するための関数です。setState関数は、1つの引数を取ります。最初の引数は、新しい状態です。

setState関数は、Reactコンポーネントの内部で使用できる、状態を更新するための関数です。setState関数は、1つの引数を取ります。最初の引数は、新しい状態です。

setState関数は、Reactコンポーネントの内部で使用できる、状態を更新するための関数です。setState関数は、1つの引数を取ります。最初の引数は、新しい状態です。

setState関数は、Reactコンポーネントの内部で使用できる、状態を更新するための関数です。setState関数は、1つの引数を取ります。最初の引数は、新しい状態です。

setState関数は、Reactコンポーネントの

8b の出力

説明を加えてくれました

import React, { useState } from'react';

const Counter = () => {
  // useStateフックを使用してカウントの状態を管理
  const [count, setCount] = useState(0);

  // カウントアップの関数
  const increment = () => {
    setCount(count + 1);
  };

  // カウントダウンの関数
  const decrement = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <h1>カウンター</h1>
      <p>現在のカウント: {count}</p>
      <button onClick={increment}>カウントアップ</button>
      <button onClick={decrement}>カウントダウン</button>
    </div>
  );
};

export default Counter;
```

このコードでは、useStateフックを使用してカウントの状態を管理しています。countという変数に現在のカウントを保持し、increment関数とdecrement関数を定義して、それぞれカウントアップとカウントダウンを行っています。

このように、ReactのuseStateフックを用いることで、簡単にカウンターアプリケーションを実装することができます。

JavaScript (Vue)

入力

<template>
  <div style="text-align: center; margin-top: 50px;">
    <h1>Counter: {{ count }}</h1>
    <button @click="increment" style="margin-right: 10px;">Count Up</button>
    <button @click="decrement">Count Down</button>
  </div>
</template>

3b の出力

中国語の Markdown に入るような形で生成されました

学習データにかなり引きずられている感じがします

<template>
  <div style="text-align: center; margin-top: 50px;">
    <h1>Counter: {{ count }}</h1>
    <button @click="increment" style="margin-right: 10px;">Count Up</button>
    <button @click="decrement">Count Down</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    },
    decrement() {
      this.count--
    }
  }
}
</script>
```

### 2.2 组件间通信

#### 2.2.1 父子组件通信

父组件向子组件传递数据

```html
<template>
  <div>
    <h1>Counter: {{ count }}</h1>
    <button @click="increment">Count Up</button>
    <ChildComponent :count="count" />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
</script>
```

子组件向父组件传递数据

```html
<template>
  <div>
    <h1>Counter: {{ count }}</h1>
    <button @click="increment">Count Up</button>
    <ParentComponent :count="count" />
  </div>
</template>

<script>
import ParentComponent from './ParentComponent.vue'

export default {
  components: {
    ParentComponent
  },
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
</script>
```

#### 2.2.2 兄弟组件通信

兄弟组件之间通过 `ref` 引用传递数据

```html
<template>
  <div>
    <h1>Counter: {{ count }}</h1>
    <button @click="increment">Count Up</button>
    <ChildComponent ref="child" />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.$refs.child.increment()
    }
  }
}
</script>
```

#### 2.2.3 跨级组件通信

跨级组件之间通过 `provide` 和 `inject` 实现

```html
<template>
  <div>
    <h1>Counter: {{ count }}</h1>
    <button @click="increment">Count Up</button>
    <ChildComponent />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.$refs.child.increment()
    }
  }
}
</script>
```

```html
<template>
  <div>
    <h1>Counter: {{ count }}</h1>
    <button @click="increment">Count Up</button>
  </div>
</template>

<script>
export default {
  provide() {
    return {
      count: this.count
    }
  },
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
</script>
```

```html
<template>
  <div>
    <h1>Counter: {{ count }}</h1>
    <button @click="increment">Count Up</button>
  </div>
</template>

<script>
export default {
  inject: ['count'],
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
</script>
```

### 2.3 事件处理

#### 2.3.1 事件绑定

```html
<template>
  <div>
    <h1>Counter: {{ count }}</h1>
    <button @click="increment">Count Up</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
</script>
```

#### 2.3.2 事件修饰符

8b の出力

説明を加えた最小限の内容になっています

<template>
  <div style="text-align: center; margin-top: 50px;">
    <h1>Counter: {{ count }}</h1>
    <button @click="increment" style="margin-right: 10px;">Count Up</button>
    <button @click="decrement">Count Down</button>
  </div>
</template>

<script>
import { ref } from 'vue';

export default {
  setup() {
    const count = ref(0);

    const increment = () => {
      count.value++;
    };

    const decrement = () => {
      count.value--;
    };

    return {
      count,
      increment,
      decrement,
    };
  },
};
</script>
```

In this code, we import the `ref` function from Vue. We then define a `count` variable using `ref` and initialize it with a value of 0.

The `increment` function is responsible for incrementing the `count` variable by 1. It simply updates the `count` value using the `value` property of the `ref` object.

The `decrement` function is responsible for decrementing the `count` variable by 1. It also updates the `count` value using the `value` property of the `ref` object.

Finally, we export the `count`, `increment`, and `decrement` functions as the default export of the component.

By using this code, you will have a Vue.js component that displays a counter and allows the user to increment and decrement the counter by clicking on the respective buttons.

bash (AWS 操作)

入力

#!/bin/bash
# 指定プレフィックス内の合計サイズを取得

if [ "$#" -ne 2 ]; then
  echo "Usage: $0 <bucket-name> <prefix>"
  exit 1
fi

BUCKET_NAME=$1
PREFIX=$2

# 指定されたバケットとプレフィックスからオブジェクトのリストを取得

3b の出力

このコードだと --key に指定する値に $PREFIX が含まれていないため、正しく動作しません

#!/bin/bash
# 指定プレフィックス内の合計サイズを取得

if [ "$#" -ne 2 ]; then
  echo "Usage: $0 <bucket-name> <prefix>"
  exit 1
fi

BUCKET_NAME=$1
PREFIX=$2

# 指定されたバケットとプレフィックスからオブジェクトのリストを取得
OBJECT_LIST=$(aws s3 ls s3://$BUCKET_NAME/$PREFIX | awk '{print $4}')

# 合計サイズを計算
TOTAL_SIZE=0
for OBJECT in $OBJECT_LIST; do
  SIZE=$(aws s3api head-object --bucket $BUCKET_NAME --key $OBJECT | jq -r.ContentLength)
  TOTAL_SIZE=$((TOTAL_SIZE + SIZE))
done

echo $TOTAL_SIZE

8b の出力

これも実は動きません

そもそも与えている入力が悪いのかな
(実は ChatGPT に生成させたコードの前半を入力にしています)

#!/bin/bash
# 指定プレフィックス内の合計サイズを取得

if [ "$#" -ne 2 ]; then
  echo "Usage: $0 <bucket-name> <prefix>"
  exit 1
fi

BUCKET_NAME=$1
PREFIX=$2

# 指定されたバケットとプレフィックスからオブジェクトのリストを取得
OBJECTS=$(aws s3api list-objects-v2 --bucket $BUCKET_NAME --prefix $PREFIX --query 'Contents[*].{Key:Key,Size:Size}' --output text)

# 合計サイズを計算
TOTAL_SIZE=0
for OBJECT in $OBJECTS; do
  KEY=$(echo $OBJECT | cut -d''-f1)
  SIZE=$(echo $OBJECT | cut -d''-f2)
  TOTAL_SIZE=$(($TOTAL_SIZE + $SIZE))
done

# 合計サイズを表示
echo "Total size of objects with prefix $PREFIX in bucket $BUCKET_NAME is $TOTAL_SIZE bytes"

指示によるコード生成

作りたいものを指示してコードを生成させます

コード生成の実行

instruction = "users の age の中央値を取得する Python 関数を生成してください"
chat = [
    { "role": "user", "content": instruction },
]
chat = tokenizer.apply_chat_template(chat, tokenize=False, add_generation_prompt=True)
input_tokens = tokenizer(chat, return_tensors="pt")

for i in input_tokens:
    input_tokens[i] = input_tokens[i].to(model.device)

with torch.no_grad():
    output_tokens = model.generate(**input_tokens, max_new_tokens=1024)

output = tokenizer.decode(
    output_tokens.tolist()[0][input_tokens['input_ids'].shape[-1]:], skip_special_tokens=True
)

print(output)

3b の場合の実行結果

偶数の場合が考慮できていません

users = [
    {"name": "John", "age": 25},
    {"name": "Alice", "age": 30},
    {"name": "Bob", "age": 28},
    {"name": "Charlie", "age": 32},
    {"name": "Dave", "age": 27},
]

def get_middle_age(users):
    sorted_users = sorted(users, key=lambda user: user["age"])
    middle_index = len(sorted_users) // 2
    return sorted_users[middle_index]["age"]

middle_age = get_middle_age(users)
print(middle_age) # 28

8b の場合の実行結果

偶数の場合まで考慮できています

users = [
    {"name": "Alice", "age": 20},
    {"name": "Bob", "age": 30},
    {"name": "Charlie", "age": 25},
    {"name": "Dave", "age": 35},
]

def get_median_age(users):
    ages = [user["age"] for user in users]
    ages.sort()
    length = len(ages)
    if length % 2 == 0:
        middle_index = length // 2
        return (ages[middle_index - 1] + ages[middle_index]) / 2
    else:
        middle_index = length // 2
        return ages[middle_index]

median_age = get_median_age(users)
print(median_age)

UI付きで実行

def chat(instruction):
    chat = [
        { "role": "user", "content": instruction },
    ]
    chat = tokenizer.apply_chat_template(chat, tokenize=False, add_generation_prompt=True)
    input_tokens = tokenizer(chat, return_tensors="pt")

    for i in input_tokens:
        input_tokens[i] = input_tokens[i].to(model.device)

    with torch.no_grad():
        output_tokens = model.generate(**input_tokens, max_new_tokens=1024)

    output = tokenizer.decode(
        output_tokens.tolist()[0][input_tokens['input_ids'].shape[-1]:], skip_special_tokens=True
    )

    return output
gr.Interface(
    fn=chat,
    inputs=[gr.Textbox()],
    outputs=[gr.Textbox()]
).launch(debug=True)

コード生成の問答集

Python 距離計算

入力

2点間の距離を計算する Python 関数を生成してください

3b の出力

説明文が日本語と英語入り混じっていて不自然です

2点間の距離は、 Pythagoras 定理に従い、 x2 + y2 = d2 です。

以下は、 Python から Pythagoras 定理を適用して 2 点間の距離を計算する Python FUNCTION を生成する方法です。

```python
import math

def distance(x1, y1, x2, y2):
    return math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
```

上記の Python FUNCTION は、 x1, y1, x2, y2 の 4 つの引数を受け取り、 x2 - x1, y2 - y1 の 2 つの引数を受け取り、 2 点間の距離を計算します。 したがって、 x1, y1, x2, y2 の 4 つの引数は、 2 点間の x, y 座標です。

8b の出力

説明文が自然になっています

2点間の距離を計算する Python 関数を生成するには、2点の座標 (x1, y1)、(x2, y2) を受け取り、distance = sqrt((x2 - x1)^2 + (y2 - y1)^2) を計算する simple_distance_function を定義します。

```python
import math

def simple_distance_function(x1, y1, x2, y2):
    distance = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
    return distance
```

x1, y1, x2, y2 を受け取り、distance = sqrt((x2 - x1)^2 + (y2 - y1)^2) を計算する simple_distance_function を定義します。distance を返します。

Python 画像処理(ガンマ補正)

入力

画像のガンマ補正を実行する Python 関数を生成してください

3b の出力

異常な出力になってしまいました

 GaussFilter() です。 GaussFilter() には、 GaussFilter.apply() があります。 GaussFilter.apply() には、 GaussFilter.apply(image, sigma) があります。 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると、 GaussFilter.apply(image, sigma) を使用すると

8b の出力

ガンマ補正できていそうです

```python
import cv2

def gamma_correction(image, gamma=1.0):
    inv_gamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** inv_gamma) * 255 for i in np.arange(0, 256)]).astype("uint8")
    return cv2.LUT(image, table)
```

Elixir 平均値取得

入力

users の age の平均値を取得する Elixir 関数を生成してください

3b の出力

いい感じのコードです

defmodule User do
  defstruct [:name, :age]
end

users = [
  %User{name: "Alice", age: 25},
  %User{name: "Bob", age: 30},
  %User{name: "Charlie", age: 28}
]

defmodule UserAge do
  def average_age(users) do
    Enum.sum(Enum.map(users, & &1.age)) / Enum.count(users)
  end
end

IO.puts(UserAge.average_age(users))

# 27.0

8b の出力

モジュールを定義せずに実装しています

reduce を使っているあたりは Elixir 好きっぽいです

users = [%{age: 20}, %{age: 30}, %{age: 40}]

Enum.reduce(users, 0, fn user, acc ->
  acc + user.age
end)
|> div(length(users))
|> IO.inspect()

# 20

Enum.reduce/3 を使い、users の age の合計を計算し、length(users)で users の個数を求め、その後に div/2 を使って average を計算します。

JavaScript (React)

入力

カウンターをボタンクリックで増減させる React のコードを生成してください

3b の出力

ちゃんとしたコードになっているようです

React では、setState() を使用してカウンター値を更新することができます。setState() を呼び出すと、カウンター値が更新され、UI が更新されます。

以下は、カウンター値を 1 増やすボタンと 1 減らすボタンを持つ React コンポーネントの例です。

```jsx
import React, { useState } from'react';

function Counter() {
  const [count, setCount] = useState(0);

  const incrementCount = () => {
    setCount(count + 1);
  };

  const decrementCount = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <p>カウンター: {count}</p>
      <button onClick={incrementCount}>+1</button>
      <button onClick={decrementCount}>-1</button>
    </div>
  );
}

export default Counter;
```

setState() を呼び出すと、カウンター値が更新され、UI が更新されます。

8b の出力

謎の挨拶から始まりましたが、いい感じです

こんにちは!

 CountyButton.js

```
import React, { useState } from'react';

const CountyButton = () => {
  const [count, setCount] = useState(0);

  const handleIncrement = () => {
    setCount(count + 1);
  };

  const handleDecrement = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <button onClick={handleIncrement}>+</button>
      <p>Count: {count}</p>
      <button onClick={handleDecrement}>-</button>
    </div>
  );
};

export default CountyButton;
```

CountyButton.jsは、stateを管理するReactの functional componentです。 stateは、countとsetCountです。 countは、ボタンを押すたびに増減する数です。 setCountは、countの状態を更新するメ소ーです。

handleIncrementとhandleDecrementは、それぞれ\+と-を押すと呼び出されます。 これらのメ소ーは、countの状態を更新します。\+を押すとcountが1増加し、-を押すとcountが1減少します。

最後に、renderメ소ーは\+と-の間にcountを表示し、それぞれのボタンをクリックするとcountが増減します。

JavaScript (Vue)

入力

カウンターをボタンクリックで増減させる Vue のコードを生成してください

3b の出力

残念ながら増やす方しか実装してくれませんでした

```html
<template>
  <div>
    <button @click="count += 1">Count: {{ count }}</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    };
  }
};
</script>
```

8b の出力

減らす方も実装できています

```html
<template>
  <div>
    <button @click="count++">Count Up</button>
    <button @click="count--">Count Down</button>
    <p>Count: {{ count }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    };
  }
};
</script>
```

count Esta prop を使用して、count Up と count Down の両方のボタンをクリックするたびに count を increment するか decrement します。count Esta prop を使用して、count Up と count Down の両方のボタンをクリックするたびに count を increment するか decrement します。

bash (AWS 操作)

入力

AWS から S3 の指定バケット、指定プレフィックス配下にあるファイルの合計サイズを取得する shell script を生成してください

3b の出力

なぜ一回バケットのリージョンを取得したのか

ちなみにこれだと合計サイズは取得できませんでした

AWS CLI を使用して、指定したバケットとプレフィックスのファイルの合計サイズを得ることができます。

以下は、AWS CLI を使用して、指定したバケットとプレフィックスのファイルの合計サイズを得る shell script の例です。

```bash
#!/bin/bash

# AWS CLI の構成
export AWS_ACCESS_KEY_ID=<your-access-key-id>
export AWS_SECRET_ACCESS_KEY=<your-secret-access-key>
export AWS_DEFAULT_REGION=<your-default-region>

# 合計サイズを得る
aws s3api get-bucket-location --bucket <your-bucket-name>
total_size=$(aws s3 ls s3://<your-bucket-name>/<your-prefix> --summarize | awk '{print $5}')
echo "Total size: $total_size"
```

上記の script を使用すると、指定したバケットとプレフィックスのファイルの合計サイズが表示されます。

注: AWS CLI を使用する前に、ACCESS KEY ID、SECRET ACCESS KEY、デフォルトリージョンを構成する必要があります。

8b の出力

スクリプトではなく、コマンド一発で取得する方法を返してくれました

S3 の指定バケット、指定プレfixes配下にあるファイルの合計サイズを取得する shell script を生成するには、aws cli を使用します。

aws s3 ls --summarize --recursive s3://<your-bucket-name>/<your-prefix>

ここで、<your-bucket-name>は、S3 バケットの名前を、<your-prefix>は、S3 バケットのプレfixesを表します。

–summarizeオプションは、結果を summaried (集計) します。
–recursiveオプションは、S3 バケットのサブフォルダー内のファイルも検索します。

この҆ コマンドは、S3 バケットの指定プレfixes配下にあるファイルの合計サイズを表示します。

まとめ

3b だと無償プランの T4 GPU でも実行できるのが良いですね

ただし、 max_new_tokens が大きいと同じ文言を繰り返しがちになったり、日本語が少し不自然だったり、コードの精度がやはり低かったりします

8b だと有償プランの L4 GPU が必要になるものの、結構良い精度でコードを生成してくれているように思います

また、どちらも日本語にちゃんと対応しているのが良いです

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1