プロンプトエンジニア

かつて検索エンジンのテクニックを学ぶように、私たちもAIとコミュニケーションをとるためのテクニックを学び、合理的で十分な制約を与え、必要な答えを効率的に得る必要があります。

もし別の角度から考えると、現在のAIは記憶力の良い子供のようなもので、一度見たものはすべて覚える能力があり、宿題を写すような能力があります。私たちがやるべきことは、AIと正しく効果的にコミュニケーションを取り、ニーズを正確に記述し、AIが期待される結果を生み出すのを助けることです。

科学普及

火が出天际のAI、正確に言うとGenerative Pre-Training(生成事前学習)です。直訳すると生成的な事前訓練となります。これは、インターネットで利用可能なデータでトレーニングされたテキスト生成深層学習モデルであり、質問応答、テキスト要約生成、機械翻訳、分類、コード生成、対話AIなどのタスクに使用されます。現在ではGPT-1、GPT-2、GPT-3、GPT-4など、さまざまなバージョンのモデルが存在し、各バージョンは前のバージョンよりも大きく、強力です。

結局、知能は存在するのか。

  • 類似度が十分高いほど、精度も上がる。
  • 基本的な、反復的な作業は、特定の訓練を経れば、もはや手作業の介在は不要となる。

生成AIとは、既存のテキスト、音声、画像などのデータを利用して新しいコンテンツを作成する技術です。テキスト生成、音声合成、画像生成、対話システムなど、さまざまなタスクに使用できます。生成AIの論理性は、トレーニングデータとモデル構造に依存します。一般的に、生成AIは文法、論理、常識をある程度遵守できますが、誤り、偏見、または虚偽の内容を生み出す可能性もあります。したがって、生成AIの出力には人間の判断と検証が必要であり、盲目的に信じたり使用したりすることはできません。

プロンプトエンジニア

時の流れは二度と戻らない、人は時代の流れに適応する必要がある。あなたはAIが賢くないとか、論理的ではないとか考えるかもしれない。それは、しばしば役に立たないコードを生成するからだ。

もし別の角度から考えると、現在のAIは記憶力の良い子供のようなもので、一度見たものはすべて覚える能力があり、宿題を写すような能力があります。私たちがやるべきことは、AIと正しく効果的にコミュニケーションを取り、ニーズを正確に説明し、AIが期待される結果を生み出すのを助けることです。

対話モード

2 年前 Github Copilot が発表されたとき、誰しも 2 年後に OpenAI が突如として現れ、人間が大規模言語モデルの能力に気づくとは思いもしなかった。

アノテーションベースのプログラミングと対話型プログラミングに基づく場合、インタラクションロジックは完全に異なり、対話形式は初心者ユーザーにとってフレンドリーな体験を提供します。この点において、NewBingが各質問の後で提示する追質問の提案は言及せざるを得ません。これは、Microsoftがユーザーを誘導し、AIナレッジベースからより多くの情報を取得しようとする試みです。

例えば

長時間の新幹線の移動中、コーディングは良い選択肢だ。データ通信量が限られているので、画像を数枚処理し、画像素材を入手した。ソフトウェアをダウンロードして画像を処理するのは少し贅沢すぎるし、ネットワーク環境もそれを許さない。

要件:一連の画像素材があり、それらは透明な背景を持つものとします。これらの画像をミニプログラムのナビゲーションバーに使用し、選択された状態はカラー表示、未選択の状態は白黒表示にしたいと考えています。素材自体はすべてカラーなので、事前に処理する必要があります。

フォルダ内のすべての画像を読み込み、画像を白黒に変換し、透明な背景を維持し、画像の品質を最適化してファイルサイズを縮小しながら画像を保存するPythonコードを作成してください。コンソールには、最適化前のファイルサイズと最適化後のファイルサイズの比較を表示します。

# 导入必要的库
import os
import PIL
from PIL import Image

# 定义一个函数,将图片转换成黑白,维持透明背景,保存图片,并返回文件体积
def convert_and_save(image_file):
    # 打开图片
    image = Image.open(image_file)
    # 获取图片的模式,如果是 RGBA 模式,说明有透明背景
    mode = image.mode
    if mode == "RGBA":
        # 创建一个和图片大小一致的白色背景图片
        background = Image.new("RGB", image.size, (255, 255, 255))
        # 将原图片粘贴到白色背景上,忽略透明像素
        background.paste(image, mask=image.split()[3])
        # 将合成的图片转换成灰度模式
        gray_image = background.convert("L")
        # 将灰度图片再转换成 RGBA 模式,以便保留透明背景
        final_image = gray_image.convert("RGBA")
    else:
        # 如果不是 RGBA 模式,直接将图片转换成灰度模式
        final_image = image.convert("L")
    # 获取原图片的文件名和扩展名
    file_name, file_ext = os.path.splitext(image_file)
    # 定义新图片的文件名,添加 _bw 后缀表示黑白
    new_file_name = file_name + "_bw" + file_ext
    # 保存新图片,并优化质量,减少文件体积
    final_image.save(new_file_name, optimize=True)
    # 获取原图片和新图片的文件体积,并返回
    old_size = os.path.getsize(image_file)
    new_size = os.path.getsize(new_file_name)
    return old_size, new_size

# 定义一个文件夹路径,存放所有的图片
folder_path = "images"
# 遍历文件夹中的所有文件
for file in os.listdir(folder_path):
    # 拼接完整的文件路径
    file_path = os.path.join(folder_path, file)
    # 判断是否是图片文件,根据扩展名判断,可以根据需要添加或修改扩展名
    if file_path.endswith((".png", ".jpg", ".jpeg", ".gif")):
        # 调用函数,转换并保存图片,并获取文件体积
        old_size, new_size = convert_and_save(file_path)
        # 在控制台展示优化前后的文件体积大小对比
        print(f"{file}: {old_size} bytes -> {new_size} bytes")

AIはすぐに答えを出力し、見た目も良く問題なく動作するものの、経験豊富なプログラマーなら、下記のコードが十分に汎用的ではなく、本番環境にデプロイするには向いていないと感じるだろう。

  • パラメータが固定されました。
  • ログファイルはなく、情報はすべてコンソールに出力されています。
  • 画像の処理タスクは、マルチスレッドモデルに適しています。

ニュービングが登場し、プロンプトに従って質問を選びました。このコードには改善できる点はありますか?

今回いただいた回答は、正直言って、完全に予想を上回っています。一般的なプログラマーが思いつくような最適化策に対して、AI が対応する提案を出してくるほどです。

这段代码可能还有一些可以改进的地方,比如:

可以使用 argparse 库,让用户可以通过命令行参数指定文件夹路径和扩展名,而不是写死在代码里。
可以使用 logging 库,记录程序的运行情况,而不是直接打印到控制台。
可以使用 try-except 语句,捕获可能出现的异常,比如文件打开失败,图片转换失败等,并做相应的处理。
可以使用 multiprocessing 库,利用多核处理器,加速图片的转换和保存过程。

非常にフレンドリーな対応で、デプロイ環境の違いを考慮し、マルチプロセスをサポートしていないことを許可します。

当然,我很乐意帮你修改一下代码。我尝试添加了 argparse, logging 和 try-except 语句,但没有添加 multiprocessing 库,因为我不确定你的电脑是否支持多核处理。修改后的代码如下:
# 导入必要的库
import argparse
import logging
import multiprocessing
import os

from PIL import Image


# 定义一个函数,将图片转换成黑白,维持透明背景,保存图片,并返回文件体积
def convert_and_save(image_file):
    # 打开图片
    try:
        image = Image.open(image_file)
    except Exception as e:
        logging.error(f"Failed to open {image_file}: {e}")
        return None, None
    # 获取图片的模式,如果是 RGBA 模式,说明有透明背景
    mode = image.mode
    if mode == "RGBA":
        # 创建一个和图片大小一致的白色背景图片
        background = Image.new("RGB", image.size, (255, 255, 255))
        # 将原图片粘贴到白色背景上,忽略透明像素
        background.paste(image, mask=image.split()[3])
        # 将合成的图片转换成灰度模式
        gray_image = background.convert("L")
        # 将灰度图片再转换成 RGBA 模式,以便保留透明背景
        final_image = gray_image.convert("RGBA")
    else:
        # 如果不是 RGBA 模式,直接将图片转换成灰度模式
        final_image = image.convert("L")
    # 获取原图片的文件名和扩展名
    file_name, file_ext = os.path.splitext(image_file)
    # 定义新图片的文件名,添加 _bw 后缀表示黑白
    new_file_name = file_name + "_bw" + file_ext
    # 保存新图片,并优化质量,减少文件体积
    try:
        final_image.save(new_file_name, optimize=True)
    except Exception as e:
        logging.error(f"Failed to save {new_file_name}: {e}")
        return None, None
    # 获取原图片和新图片的文件体积,并返回
    old_size = os.path.getsize(image_file)
    new_size = os.path.getsize(new_file_name)
    return file_name, old_size, new_size

# 定义一个函数,解析命令行参数,并返回文件夹路径和扩展名列表
def parse_args():
    # 创建一个解析器对象
    parser = argparse.ArgumentParser(description="Convert images to black and white and optimize quality.")
    # 添加一个必选的位置参数,表示文件夹路径
    parser.add_argument("folder_path", help="The path of the folder that contains the images.")
    # 添加一个可选的参数,表示扩展名列表,默认为 png, jpg, jpeg 和 gif
    parser.add_argument("-e", "--extensions", nargs="+", default=[".png", ".jpg", ".jpeg", ".gif"], help="The extensions of the image files.")
    # 解析命令行参数,并返回结果对象
    args = parser.parse_args()
    return args.folder_path, args.extensions

# 定义一个函数,打印优化前后的文件体积大小对比
def print_result(result):
    # 如果结果不为空,说明转换和保存成功
    if result:
        # 解包结果为文件名和文件体积元组
        if len(result) == 3:
            file, old_size, new_size = result
            # 在控制台展示优化前后的文件体积大小对比
            logging.info(f"{file}: {old_size} bytes -> {new_size} bytes")
        else:
            logging.info(f"{result}")

# 配置日志记录器,将日志输出到控制台和文件中,设置日志等级为 INFO
logging.basicConfig(level=logging.INFO,
                    format="%(asctime)s %(levelname)s %(message)s",
                    handlers=[logging.StreamHandler(),
                              logging.FileHandler("log.txt")])

# 调用函数,获取文件夹路径和扩展名列表
folder_path, extensions = parse_args()

if __name__ == "__main__":
    # Windows 需要这个函数的原因是 Windows 缺乏 fork() 函数(这不完全正确)。
    # 因此,在 Windows 上,fork() 是通过创建一个新的进程来模拟的,这个新的进程中运行的代码,在 Linux 上是在子进程中运行的。
    # 由于这些代码要在技术上无关的进程中运行,所以它必须在运行之前被传递到那里。
    # 传递的方式是先将它们序列化,然后通过管道从原始进程发送到新的进程。
    # 另外,这个新的进程被通知它必须运行通过管道传递的代码,通过向它传递 --multiprocessing-fork 命令行参数。
    # 如果你看一下 freeze_support() 函数的实现,它的任务是检查它运行在哪个进程中,是否应该运行通过管道传递的代码
    multiprocessing.freeze_support()

    # 创建一个进程池,根据电脑的核心数自动分配进程
    pool = multiprocessing.Pool()
    # 创建一个空列表,用于存放异步任务的结果对象
    results = []
    # 遍历文件夹中的所有文件
    for file in os.listdir(folder_path):
        # 拼接完整的文件路径
        file_path = os.path.join(folder_path, file)
        # 判断是否是图片文件,根据扩展名判断,可以根据需要修改扩展名列表
        if any(file_path.endswith(ext) for ext in extensions):
            # 调用函数,转换并保存图片,并获取文件体积,使用异步方式,不阻塞主进程
            result = pool.apply_async(convert_and_save, args=(file_path,), callback=print_result)
            # 将结果对象添加到列表中
            results.append((file, result))
    # 关闭进程池,不再接受新的任务
    pool.close()
    # 等待所有的任务完成
    pool.join()

あとがき

ローカル開発環境がWindowsシステムであるため、AIが最初に提示した回答にはmain関数もmultiprocessing.freeze_supportも含まれていませんでした。質問への対応でエラーが発生し、それによってコードを修正しました。

かつて検索エンジンのテクニックを学ぶように、私たちもAIとコミュニケーションをとるためのテクニックを学び、合理的で十分な制約を与え、必要な答えを効率的に得る必要があります。

注意:プログラミング初心者の方で、与えられたコメントに基づいて理解できない部分があれば、関連コードについてさらに質問してください。

Licensed under CC BY-NC-SA 4.0
最終更新 2025年05月25日 14:10
金融ITプログラマーのいじくり回しと日常のつぶやき
Hugo で構築されています。
テーマ StackJimmy によって設計されています。