生産がす
なんか げーむ つくったり とか してます
2026年3月9日月曜日
いめーじぺたぺた ver2.00
■ダウンロード
file: imgPt_v200.zip
size: 195KB
分類: フリーソフト
MD5: 954af7a1c1546b572f0a73394174b6c9
■概要
ゲーム用画像を作成するときの、
一定サイズの画像を一定間隔に並べる作業をサポートする画像設置ツールです。
読み書きにBMP,PNG対応
グレースケール画像を使用してアルファチャンネルを編集できます。
■動作環境
Windows 11
CPU 2GHz以上
メモリ 1GB以上
■アンインストール
レジストリは触っておりません。
削除の際はフォルダごとゴミ箱へどうぞ。
■使い方
【ファイル操作】
Ctrl + O : 画像ファイルを開く
Ctrl + Shift + O : クリップボードから画像を開く
Ctrl + S : 画像を保存
【編集・選択】
Ctrl + Z : 元に戻す (Undo)
Ctrl + Y または Ctrl + Shift + Z : やり直し (Redo)
Ctrl + C : 選択範囲をコピー
Ctrl + X : 選択範囲を切り取り
Ctrl + V : 貼り付け
Ctrl + Shift + V : 半透明合成で貼り付け
Ctrl + A : キャンバス全体を選択
【表示・設定】
Ctrl + 0 (ゼロ) : 拡大率を100%(x1)に戻す
N : 透明度を反映するかどうかの表示切り替え
Ctrl + E : キャンバスサイズの変更ウィンドウを開く
Ctrl + G : グリッドサイズの変更ウィンドウを開く
【色操作・置換】
Ctrl + I : 色の反転
Ctrl + R : 色置換ウィンドウを開く
Ctrl + T : 現在の設定で「色置換」を実行
T : (マウス下の色を)「置換元」の色に設定
Shift + T : (マウス下の色を)「置換後」の色に設定
【マウス操作(共通)】
ホイール回転 : 拡大・縮小(カーソル位置中心)
ホイールクリック+ドラッグ : キャンバスの表示位置を移動(パン)
左ダブルクリック : 選択範囲をクリップボードの画像サイズに合わせる
(ダブルクリック後)ドラッグ : 選択範囲をグリッド単位で移動
■そのほか
このソフトウェアを使用し、何らかの障害が発生しても責任を取りかねますのでご了承ください。
zlibライブラリを使用しています。
Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
http://www.winimage.com/zLibDll/
libpngライブラリを使用しています。
Copyright (c) 1998-2007 Glenn Randers-Pehrson
http://www.libpng.org/
JSON for Modern C++ (nlohmann/json)
Copyright (c) 2013-2025 Niels Lohmann
https://github.com/nlohmann/json
■更新履歴
2026-01-16 ver2.00
64bit用にコード書き直し
2021-09-30 ver1.09
乗算済みアルファ化する機能を追加。
および乗算済みアルファから元に戻す機能を追加。
2020-07-25 ver1.08h
ファイル保存時のファイル出力種類選択がおかしくなっているのを修正
選択範囲をファイル出力時にBitmap32のときのみ保存に成功してもエラー表示されるのを修正
2020-03-12 ver1.08g
スペースキーを押しながらホイール回転で、拡大縮小表示の倍率を小さく変更できるよう修正
UNICODE化
ファイルリストの表示を長いファイルパスでも表示できるよう修正
各ウィンドウを手書きからリソースエディタ使用に切り替え、ボタン等の配置を修正。
透明部分の表示色を変更できる機能を追加
2020-03-05
複数ファイルをD&D起動および「送る」起動のときの処理順序が間違ってるぽいので直した
複数ファイルをD&D起動および「送る」起動の場合、
画像ファイルパスコピー時に反映されないのを確認したので、上記に修正
2015-12-02
複数ファイルをD&D起動および「送る」のときにファイルパスを正しく取得できていなかったのを修正
2015-11-15 ver1.08f
どこ触ったかわからない(笑)が実行ファイルの更新日時が新しかったので実行ファイル上書き。再圧縮。
2015-07-26 ver1.08f
非アクティブの時はクリップボードのチェックしないよう修正。アクティブになった瞬間再チェックします。
Shift+Ctrl+ZでRedoが機能するように修正
グリッドサイズ変更ウィンドウでカーソルがウィンドウ外にあるときに非アクティブになる機能を廃止
グリッドサイズに1x1と2x2, 256x256を選択できるよう修正
拡大倍率にx16を選択できるよう修正
2015-06-23 ver1.08e
クリップボードチェインからリスナーへ変更。XP以下では動作不可に
2014-03-13 ver1.08d
「指定色を変更」の「元の色」が正しく記録されないのを修正
libpngを最新のものに。(ver1.6.9)
2012-12-27 ver1.08c
libpngを最新のものを適用v1.5.13
2012-12-27 ver1.08c
「指定色で透明化」を使用しても画像を変更した*マークがつかないのを修正
「指定色の変更」をモードレスダイアログ化し、色をリアルタイムで確認可能に
TキーおよびShift+Tキーによる色の取得を画像範囲内に限定
ステータスバー内グリッド選択領域で左クリックでグリッド選択ウィンドウを出すよう修正
2012-09-18 ver1.08b
「左右反転」「上下反転」機能を追加
設定でアンドゥバッファの最大数を変更できるよう修正
半透明貼り付けの座標計算が間違っているのを修正
2012-02-14
マニフェストファイルの記述を修正
2011-07-31 ver1.08a
最小化したときスクロールバーの位置が変わるのを修正
2011-05-28 ver1.08
マウスの進む、戻るボタンに対応
2010-11-18 ver1.07b
読み込み可能なファイルを制限
[.bmp][.dib][.png][.jpeg][.jpe][.jpg][.gif]のみ読み込み可能
2010-08-21 ver1.07
「範囲外を超えて貼り付け」機能を追加
「半透明合成」機能を追加
「下地を不透明で半透明合成」機能を追加
「拡大縮小処理の動作」設定を可能に
2010-07-19 ver1.06
「マスクのコピー」機能を追加
「マスクをファイルに出力」で横幅が4の倍数でないときに正常に保存できないのを修正
「使用色カウント」が範囲外を選択中でも使用可能なのを修正
コピーデータビューアでホイール押し込みでも画像の表示移動が可能なように修正
起動→「開く」の場合は更新マークが付いてしまうのを修正
更新マークがついてないときに「開く」を行っても、更新マークが付かない
ファイル保存ウィンドウに表示されるファイル名を、拡張子なしになるよう修正
2010-07-16 ver1.05c
起動直後の「開く」のときは更新マークをつけないように修正
2010-07-14 ver 1.05b
「指定色を変更」の指定色の透過率を維持するよう修正
2010-07-10 ver1.05
ドロップ起動に対応
ファイルリストウィンドウのサイズを大きく
2010-03-23 ver1.04
ファイルリストから貼り付けたときの「サイズを自動拡張する」の拡張サイズが間違っているのを修正
そのときメインウィンドウのスクロールバーが変化しないのを修正
ファイルリストの選択を動かしたときに、ウィンドウタイトルが変更されないのを修正
ファイルリストで「開く」を押したときに、メインウィンドウのタイトルにファイル名が表示されていないのを修正
「現在の選択範囲でグリッド設定」機能を追加
選択範囲を画面外まで広げたときに選択範囲線がちゃんと再描画されないのを修正
2010-02-28 ver1.03
ファイルリストから貼り付けたとき、
「サイズを自動拡張する」チェックが入っていると、アンドゥバッファを最大に使用するミスを修正
D&Dで貼り付けたとき「サイズを自動拡張する」チェックが入っていると、アンドゥバッファを最大に使用するミスを修正
ファイルリストにファイルがないときにドラッグするとリストがおかしくなるのを修正
ファイルリストの「リストの選択を移動する」動作時に、リストの最後までいくとリスト選択状態を解除するよう修正
ファイルリストに横スクロールバーを640ピクセルで作成。文字サイズの取得の仕方がわからん;;。
グリッドサイズに256x256と512x512を追加
2010-02-08
「サイズを自動拡張する」のときに範囲外に貼り付けてもスクロールバーが更新されていないのを修正
選択範囲を右に1ドット、下に1ドット広く表示するよう修正
ファイル保存のときの種類選択を記憶するよう修正
2010-01-28 ver1.02
「サイズを自動拡張する」の拡張サイズ計算が間違っていたのを修正
グリッド位置の動作仕様を変更
ファイルリストの「選択範囲を動かす」の動作を仕様変更にあわせて修正
2010-01-27 ver1.01
色数カウント機能を追加
バックバッファが終了時にメモリリークしていたのを修正
2010-01-03 ver1.0
clipboard ver2.00
■ダウンロード
file: clipboard_v200.zip
size: 196KB
分類: フリーソフト
MD5: 04c8e7610b9f6083c0b981de5f68992a
■概要
●クリップボードのデータを保持するアプリケーションです。
保持したデータはリストからコピーしたりファイルに出力が可能です。
●初期設定では256個までのデータを保持でき、それ以上のデータはリストの下の物から消えていきます。
設定を変更すると最大で65536個までのデータを保持できます。
●よく使うデータは固定リストに登録すると便利です。固定リストへは65536個まで保存できます。
固定リストへはD&Dで登録できます
●保持するデータはデフォルトの場合、
・テキスト
・ファイルのコピーや切り取り
・画像
・WAVE
・HTMLデータ
・SYLK形式のデータ(エクセルのセルなど)
です。フォーマットリストを編集することで対応フォーマットを追加や削除、保持するデータのサイズなどの設定することができます。
●マウスホイールを押したまま上か下へ回すと、リストのメニューを表示することができます。 キーボードショートカットの場合、ctrl+shiftを2回でリストのメニューを表示できます。
●データを圧縮、暗号化して保持します。
■動作環境
Windows 11
CPU 2GHz以上
メモリ 2GB以上
■アンインストール
レジストリは触っておりません。
削除の際はフォルダごとゴミ箱へ。
■使い方
リストの項目を右クリックすることで、以下の高度な操作が可能です:
・コピー
複数の項目を一つにまとめてコピーできます
テキストは改行してひとつにまとめられます
・テキストでコピー
ファイルパスやHTMLなどを、強制的にプレーンテキストとしてコピーします。
・ファイルでコピー
テキストをファイルパスとしてコピーします
・ファイル切り取り
ファイルを切り取り状態にします
・ファイルに保存
内容をファイルとして書き出します
・ビューワで見る
選択データ内容をビューワで見ることができます
・サウンド再生
WAVE形式のデータを再生できます
停止は「その他」→「サウンドの停止」から停止できます
・メニュー文字を編集
ショートカットメニューやリストに表示されている文字を編集できます
固定リストでの表示をわかりやすくするのに便利です
・固定リストに登録
選択項目をウィンドウ下部の固定リストに登録します
選択項目をD&Dでも登録することができます
固定リストの項目はD&Dで位置を入れ替えることができます
・プロパティ
圧縮の有無、暗号化の有無などの、内部情報を表示します。
■設定など
●フォーマットリスト
保持するクリップボードのデータの設定を行います。Windowsのクリップボードの仕様に詳しい方向け。
項目をダブルクリックで編集。
右クリックメニューから新規に追加、削除ができます。
・フォーマット
標準フォーマット、ID、識別子のいずれかをしようしてクリップボードのデータを識別します
・保持する最大サイズ
設定したサイズ以上のデータは無視するようになります
・重複チェックするサイズ
指定サイズまでデータを比較し、合致していなければリストに含めるようにします
比較は、前回クリップボードにコピーされたデータと行われます
・圧縮サイズ
指定サイズ以上のデータは圧縮して保存します
・暗号化を行う
保存するときに暗号化を行うようにします
暗号化はWindowsユーザー情報を使用するので、別のユーザーや別のPCからは暗号化が解読できなくなります
・メニューでの表示名
履歴リスト、固定リストの「種類」に表示される表示名を設定できます
・ファイル出力時のデフォルト拡張子
履歴リスト、固定リストでの、右クリックメニューから「ファイルに保存」したときの拡張子を設定できます
「.txt」「.bmp」など。ドットを必ずつけてください
・リストの背景色
履歴リスト、固定リストでの項目背景色を設定できます
●コンフィグ
・履歴リスト
履歴をいくつまで残すか決められます(最大65536個)
保持できる最大数を超えると、履歴リストの下にあるものから消えていきます
数を増やすと過去のデータを探しやすくなりますが、その分ファイルサイズが大きくなります
・ショートカットメニュー
マウスやキーの操作でパッと出てくるメニューに、最新の履歴をいくつ表示するか設定します。
・オートセーブ
PCの不具合やソフトの強制終了対策に、
それまでの履歴が消えないように一定時間ごとにデータを自動で書き出します
・マウスショートカット
「ホイール押し下げ + 回転」で、ショートカットメニューを表示するようにします
・キーボードショートカット
shiftやctrlキーを連打したときに、ショートカットメニューを表示するようにします
・キー押し込み間隔
「連打」と判定されるまでの時間の長さです
数値を大きくすると、ゆっくり押しても反応するようになります。
●再構築
ファイルに保存されているクリップボードデータを最適化して再構築します。
保存ファイル内データの断片化が解消されファイルが小さくなります
●保存
固定リスト、履歴リスト、コンフィグなどの情報を直ちに保存します
●クリップボードクリア
現在のクリップボードに保持されているデータを消去します
パスワードなどの機密情報をコピーした後に使うと安全です。
●サウンドの停止
リスト右クリックから再生したあと、再生中のサウンドデータを停止させます。
■そのほか
このソフトウェアを使用し、何らかの障害が発生しても責任を取りかねますのでご了承ください。
■ver1シリーズとの違い
・64bit化
・重複チェックを一つ前のデータとだけ行う
・圧縮、暗号化でシングルスレッドで行う
・暗号化処理をWindowsの仕様に準じたものに
■更新履歴
2026-01-10
クリップボード更新時の一部フォーマットはデータサイズを取得できずに落ちるのを修正
2025-12-27
メニュー選択後に元のウィンドウにアクティブを移す処理を追記
2025-12-07
ソースコードをコンパクトにするため、機能を最小限に
2025-11-15
64bit化
2021-10-22 ver1.00e
ショートカットメニューを解除時にアクティブウィンドウを戻す処理を改善
2019-11-17 ver1.00d
ウィンドウ生成周りの処理が間違っていたのを修正
ショートカットメニューを消す処理の条件をより限定的に修正
2019-09-18 ver1.00c
ショートカットメニューが消えずに残るのを修正
2018-10-02 ver1.00b
ショートカットメニュー使用後元のウィンドウにアクティブを返すよう修正
2018-08-04 ver1.00a
SetFilePointer を SetFilePointerEx に変更
2018-03-10 ver1.00
2025年12月10日水曜日
FolderPathLogger ver1.01a
■ダウンロード
FolderPathLogger101a.zip
size: 116KB
md5: 576514eeb43ef329f6f782827fd7d0a9
分類: フリーソフト
■概要
表示したフォルダのパスを収集します。
間違って閉じてしまったときや、深い位置にあるフォルダをたどるのが面倒な時などにどうぞ。
■動作環境
Windows 11
CPU 2GHz以上
メモリ 2GB以上
■アンインストール
レジストリは触っておりません。
削除の際はフォルダごとゴミ箱へ。
■使い方
起動中はエクスプローラで表示したフォルダのパスを自動で収集します、
●リスト右クリックメニュー
Open Dir - 指定フォルダを開きます
Copy as Text - 指定フォルダのパスをテキスト形式でコピ。複数選択時は改行してコピーします
Select All - 項目を全選択
Deselect - 選択を解除
Remove - 選択している項目を削除
Remove All - 全項目を削除
Remove Invalid Paths - 存在しないフォルダのパスであれば、項目を削除
Search - 検索欄に入力された文字に合致するパスを表示するようにします
●ウィンドウメニュー
save - リストとコンフィグを直ちに保存します
exit - プログラムを終了します
config - コンフィグウィンドウを表示
Version - バージョン情報を表示
●コンフィグウィンドウ
最大保持数 - リストに保持できる項目の最大数
オートセーブ - リストとコンフィグの自動保存周期の設定
項目の背景色 - パスのドライブ別の背景色を設定できます。
色は「色の設定ウィンドウ」の「作成した色」のものから使用されます
重複パスをスキップ
前回と同じパスを確認したときにリストに追加しないようにします
■そのほか
このソフトウェアを使用し、何らかの障害が発生しても責任を取りかねますのでご了承ください。
minizを使用しています
Copyright 2013-2014 RAD Game Tools and Valve Software
Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
■更新履歴
2025-11-25 ver1.01a
最大化時にリストのサイズ更新が行われていないのを修正
2025-11-12 ver1.01
64bit化
アクティブウィンドウの変更感知にSetWinEventHookを使用するように変更。
エクスプローラのパス変更をIConnectionPointContainerを使用するよう変更。
試しにリストデータの圧縮保存にminizを使用するよう変更
リストデータのメモリをメモリプールから取得するよう変更
前バージョンとの違い
コンパクトパスを削除
リスト項目の背景色をドライブ別のみに
フォルダコピー機能を削除
2020-05-25 ver1.00c
エクスプローラからパスを得るためのデータを最小限だけ保持するよう変更
2020-05-24
エクスプローラからパスを得るためのデータを保持しない仕様に変更。
2019-11-18 ver1.00b
ウィンドウ生成周りが間違っていたのを修正
2019-03-26 ver1.00a
windowsに処理負担がかかりHookが死ぬ場合に備えて、Hookしなおす処理を追加
2018-10-22 ver1.00
公開
2025年11月13日木曜日
FolderPathLogger ver1.01
■ダウンロード
FolderPathLogger101.zip
size: 113KB
md5: 3d134fcca1d69d0a71edfbb137c2f3a8
分類: フリーソフト
■概要
表示したフォルダのパスを収集します。
間違って閉じてしまったときや、深い位置にあるフォルダをたどるのが面倒な時などにどうぞ。
■動作環境
Windows 11
CPU 2GHz以上
メモリ 2GB以上
■アンインストール
レジストリは触っておりません。
削除の際はフォルダごとゴミ箱へ。
■使い方
起動中はエクスプローラで表示したフォルダのパスを自動で収集します、
●リスト右クリックメニュー
Open Dir - 指定フォルダを開きます
Copy as Text - 指定フォルダのパスをテキスト形式でコピ。複数選択時は改行してコピーします
Select All - 項目を全選択
Deselect - 選択を解除
Remove - 選択している項目を削除
Remove All - 全項目を削除
Remove Invalid Paths - 存在しないフォルダのパスであれば、項目を削除
Search - 検索欄に入力された文字に合致するパスを表示するようにします
●ウィンドウメニュー
save - リストとコンフィグを直ちに保存します
exit - プログラムを終了します
config - コンフィグウィンドウを表示
Version - バージョン情報を表示
●コンフィグウィンドウ
最大保持数 - リストに保持できる項目の最大数
オートセーブ - リストとコンフィグの自動保存周期の設定
項目の背景色 - パスのドライブ別の背景色を設定できます。
色は「色の設定ウィンドウ」の「作成した色」のものから使用されます
重複パスをスキップ
前回と同じパスを確認したときにリストに追加しないようにします
■そのほか
このソフトウェアを使用し、何らかの障害が発生しても責任を取りかねますのでご了承ください。
minizを使用しています
Copyright 2013-2014 RAD Game Tools and Valve Software
Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
■更新履歴
2025-11-12 ver1.01
64bit化
アクティブウィンドウの変更感知にSetWinEventHookを使用するように変更。
エクスプローラのパス変更をIConnectionPointContainerを使用するよう変更。
試しにリストデータの圧縮保存にminizを使用するよう変更
リストデータのメモリをメモリプールから取得するよう変更
前バージョンとの違い
コンパクトパスを削除
リスト項目の背景色をドライブ別のみに
フォルダコピー機能を削除
2020-05-25 ver1.00c
エクスプローラからパスを得るためのデータを最小限だけ保持するよう変更
2020-05-24
エクスプローラからパスを得るためのデータを保持しない仕様に変更。
2019-11-18 ver1.00b
ウィンドウ生成周りが間違っていたのを修正
2019-03-26 ver1.00a
windowsに処理負担がかかりHookが死ぬ場合に備えて、Hookしなおす処理を追加
2018-10-22 ver1.00
公開
2025年10月26日日曜日
windowCap ver1.04
■ダウンロード
windowCap104.zip
size: 170KB
分類: フリーソフト
MD5: 7b113a7d46ddede220ef03b8db483cba
■概要
PrintScreenが押されると、ウィンドウのスクリーンショットを撮って画像ファイルで出力します。
対応出力形式:BMP、PNG
ShiftやCtrl、Altキーの同時押しによる、キャプチャ範囲の個別設定が可能。(3つまで)
音とバルーン表示でわかりやすく出力確認。
出力ファイル名に日付を入れるといった、ちょっとだけ柔軟な名前設定もできます。
■動作環境
Windows 11
CPU 1GHz以上
メモリ 1GB以上
■アンインストール
レジストリは触っておりません。
削除の際はフォルダごとゴミ箱へ。
■使い方
1. キー設定
キャプチャ方法と保存アクションを設定します。最大3つのキー設定を登録できます。
スクリーンショットのキー設定
キャプチャを実行するキー(PrintScreen固定)と同時に押す修飾キー(Shift、Ctrl、Alt)を設定します。
複数設定の同時実行
3つの設定で同じ記録キーを使用した場合、設定された範囲すべてがキャプチャされ、複数枚の画像ファイルが出力されます。
クリップボード出力時の優先度
クリップボードへ出力する場合、設定リストの下側に登録された設定が優先されます。
記録する画面の範囲(キャプチャ範囲)
・なし
キーが押されても何もしません。(設定を無効化したい場合に)
・メインディスプレイ
メイン画面全体をキャプチャします。
・アクティブウィンドウ
現在操作しているウィンドウ全体(枠、タイトルバー含む)をキャプチャします。
・アクティブウィンドウのクライアント領域
現在操作しているウィンドウから、タイトルバーなどの枠を除いた中身の領域のみをキャプチャします。
・カーソル下のウィンドウ
マウスカーソルの直下にあるウィンドウ全体をキャプチャします。
・カーソル下のウィンドウのクライアント領域
マウスカーソルの直下にあるウィンドウの中身の領域のみをキャプチャします。
・各ディスプレイを個別ファイル
マルチディスプレイ環境で、各画面を別々の画像ファイルとしてキャプチャします。
ファイル名には自動で (1), (2) などが追記されます。
※ クリップボード出力ではメインディスプレイのみが対象になります。
・カーソル下のメインディスプレイ
マウスカーソルがあるディスプレイ全体をキャプチャします。
・全ディスプレイを結合
ディスプレイ全部を範囲とします
マウスカーソルを含める
チェックをいれると、キャプチャ画像にマウスカーソルの形を含めます。
出力先
キャプチャした画像の保存方法を「ファイル」または「クリップボード」から選択します。
2. 通知設定
ポップアップ通知
キャプチャ成功時、画面端にポップアップ通知を表示してお知らせします。
完了音を鳴らす
キャプチャ成功時、音を鳴らしてお知らせします。
※ 実行ファイルと同フォルダにある sound.wav を置き換えることで、好きな音に変更できます。
3. ファイル設定
ファイル形式
保存する画像ファイルの形式を ビットマップ (.bmp) または PNG (.png) から選択します。
上書き時に確認ウィンドウを出す
ファイル名が既存のファイルと重複した場合に、上書きするかどうかを確認するダイアログを表示します。
※ チェックなしの場合、自動で上書きされます。
出力先フォルダ
画像ファイルが保存されるフォルダを指定します。指定フォルダが存在しないとファイルは出力されません。
[...]ボタン
フォルダ選択ウィンドウを開き、出力先フォルダを設定できます。
※ フォルダが存在しない場合、画像が保存されないので注意してください。
出力先フォルダを開く
現在設定されている保存先フォルダをエクスプローラーで開きます。
ファイル名
画像ファイル名を自由に設定できます。
禁止文字
ファイル名には「\」「/」?」「*」「"」「>」「<」「|」の文字は設定できません。
自動置換コード
以下のコードを使用すると、自動的に日付・時刻・連番の数値に置き換えられます。
「%y」年4桁 例: 2015
「%Y」年(下2桁) 例: 15
「%m」月 例: 2
「%M」月(下2桁) 例: 02
「%d」日 例: 3
「%D」日(2桁) 例: 03
「%h」時 例: 1
「%H」時(2桁) 例: 01
「%i」分 例: 1
「%I」分(2桁) 例: 01
「%s」秒) 例: 1
「%S」秒(2桁)) 例: 01
「%l」ミリ秒) 例: 23
「%L」ミリ秒(3桁)例: 023
「%n」連番値 例: 12
「%%」文字の% 例: %
ファイル名例
[%y%m%d]cap%n → [2015213]cap0001
[%Y%M%d]cap%n → [150213]cap0001
[%Y-%M-%d]cap%n → [15-02-13]cap0001
[%y%M%d_%H%I%S]cap%n → [20150213_010101]cap0001
拡張子はファイル形式で設定した形式(例:.png)が自動的に付与されます。
連番値
画像が出力されるごとに+1されていく数値です。ファイル名設定の %n で使用されます。
連番桁数
ファイル名に %n を使用したとき、連番の桁数を設定します。
例: 4桁設定時、連番値が 1 ならファイル名には 0001 と出力されます。
4. 画像メモリをキャッシュする
キャプチャにつかったメモリを破棄せずにとっておくことで高速化を図ります
5. キーチェックを正確に行う
グローバルフックを使いキー入力のタイムラグがほぼ0になるよう努めます
■そのほか
このソフトウェアを使用し、何らかの障害が発生しても責任を取りかねますのでご了承ください。
zlibライブラリを使用しています。
zlib software copyright ? 1995-2022 Jean-loup Gailly and Mark Adler.
https://zlib.net/
libpngライブラリを使用しています。
* Copyright (c) 1995-2025 The PNG Reference Library Authors.
* Copyright (c) 2018-2025 Cosmin Truta.
* Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
* Copyright (c) 1996-1997 Andreas Dilger.
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
https://www.libpng.org/
■更新履歴
2025-10-26 ver 1.04
64bit化
バルーンをクリック時に保存先フォルダを表示可能に
「全ディスプレイを結合」設定を追加
いくつかの設定名をわかりやすいよう変更
(1.01,1.02,1.03台のソースコードがどっか行ったので書き直した)
2015-02-15 ver 1.00a
終了確認メッセージウィンドウが出ているときにキャプチャすると強制終了していたのを修正
2015-02-14 ver 1.00
2025年8月27日水曜日
簡易そろばん (12桁)
簡易そろばん (12桁)
現在の値: 0
*要javascript
意外にそろばんを操作できるだけのウェブページが見当たらなかったの自作しました。
そろばん5級相当の問題をランダムで作成
足し算問題の途中経過が欲しくて問題作成機能を作ってみました。
2025年2月6日木曜日
Fスクリーンキーボード ver3.1c
■ダウンロード
File: fkey310c.zip
Size: 724KB
MD5: 67a1465080e5864acfc93f0693280253
分類: フリーソフト
■概要
スクリーンキーボードにフリック機能をつけて、ctrlやshiftへのカーソル移動の手間を少し減らすことができます。
従来の日本語キーボードの他に、日本語フリック入力用のレイアウトや、テンキーや50音キーボードなども使用できます。
■動作環境
Windows 10 (64bit)
CPU 2GHz以上
メモリ 4GB以上
■アンインストール
レジストリは触っていません。
削除の際はフォルダごとゴミ箱へ。
■使い方
・表示されているキーを左クリックすることでキー入力できます。
・フリック(クリックしたままカーソルを移動し、指を離す)することで
ShiftやCtrlキーを付加したり、関連したキーを押すことができます。
・右クリックフリックで最小化やコンフィグ表示、レイアウト変更などを行うことができます。
右クリックフリックは設定で自由に変更できます
詳しくはhelp.htmlを参照してください。
■そのほか
このソフトウェアを使用し、何らかの障害が発生しても責任を取りかねますのでご了承ください。
■更新履歴
2025-02-05 ver 3.1c
アクティブ時間が500ms以上のウィンドウがアクティブ化対象になるよう修正
2022-09-29 ver 3.1b
スタンバイ時、再起動時に設定を保存するよう修正
2022-07-14 ver 3.1a
テンキーのEnterキーにextendedフラグを付与してみる
2022-04-29 ver 3.1
64ビット化
「前のディスプレイへ移動」「次のディスプレイへ移動」のシステムフリック項目を追加
タイトルバー非表示のときに閉じるボタン等が動作しないように修正
コンフィグウィンドウの表記と動作を少し修正
「ローマ字入力」「スキャンコードを使用」の二つを有効にしているときに、ひらがなの入力がうまく入力できないのを修正
2022-02-16 ver 3.01
デフォルトサイズの1.25倍~4倍のサイズに変更するシステムフリック項目を追加
2022-01-08 ver 3.00b
最小化した状態で終了すると、次に起動時にウィンドウがどっか行く問題を修正。
最小化状態でシステムメニューを出したとき、別ウィンドウアクティブ化する機能が働いてシステムメニューが閉じられてしまう問題を修正。
2021-06-02 ver 3.00a
テンキーexの追加。
スキャンコード使用時のコードが間違ってるのを修正-
2021-02-07 ver 3.00
2023年1月10日火曜日
pointClick ver 2.00d
■ダウンロード
File: pointClick200d.zip
Size: 68KB
分類: フリーソフト
MD5: 8a7d21f79e995d01df32ae8fffa8233c
■概要
クリックしたときに、マウスがちょっと動いてしまってドラッグ&ドロップになってしまうのを防ぎます。
■動作環境
Windows 10 (64bit)
CPU 2GHz以上
メモリ 2GB以上
■アンインストール
レジストリは触っておりません。
削除の際はフォルダごとゴミ箱へ。
■使い方
起動中、クリック開始位置と終了位置が近ければカーソル位置を補正するようになります。
不要になったら終了してください。
■ver1台との違い
クリックに情報を乗せられることに気が付いたので、それを利用してプログラムをシンプルにしました。
マウスのボタンを押してからクリックさせるまでの間に、クリック先ウィンドウが補正機能対象かチェックするようにしました
権限が上と思われるソフトに対して、全機能がオフになる処理を入れました
■設定の説明
○マスター on/off
オフにすると補正機能が動かなくなります。一時的に補正したくないときなどに。
○左クリック、ホイールクリック、右クリック
チェックがついているものだけ補正機能が働きます。
○有効時間
マウスのボタンを押してから離すまでの時間設定
設定した時間よりも長くマウスのボタンを押されていると、位置補正機能は働きません
○有効距離
マウスのボタンを押してから離すまでに移動した距離の設定
設定した距離よりも長く移動していたら、位置補正機能は働きません
○クリック時間
補正機能が実行されたときにクリックされている時間の設定
いくつかのアプリケーションではクリック時間が短すぎるとクリックされたと認識しないことがあります。
○有効アプリを限定する
補正機能が働くアプリケーションを限定することができます
○アプリ選択
補正機能が働くアプリケーションを選択できます
○ログ表示
補正機能が働いたかどうかのログを表示します
○ログ表示数
ログを表示する数の設定
■そのほか
このソフトウェアを使用し、何らかの障害が発生しても責任を取りかねますのでご了承ください。
■更新履歴
2023-01-07 ver 2.00d
新規ウィンドウをクリックしたときのフックし直す処理を最適化。
2021-03-08 ver 2.00c
D&D開始時の位置がずれる問題を軽減できるよう修正。他のアプリケーションの処理サイクルやPC全体の負担具合によって機能したりしなかったりします。
2020-12-17 ver 2.00b
最小化時に終了して、使い起動時に最小化状態が維持していないのを修正
2019-11-10 ver 2.00a
権限が上と思われるソフトがアクティブのときは、全機能オフにするよう修正
2022年12月20日火曜日
C++ neural networkの勉強
■行列を使うタイプのニューラルネットワークを作ってみました。
参考にしたのは
10.1: Introduction to Neural Networks - The Nature of Code https://www.youtube.com/watch?v=XJ7HLz9VYz0
C++ neural networks from scratch - Pt 1. building a matrix library https://www.lyndonduong.com/linalg-cpp/
まずは作ってみようと思って作ったのがこちら。
[ソースコード]
ちょっと前に作ったjavascript版のニューラルネットワークと同様に、
HTMLカラーコードを学習させることにしました。
xor以外で手ごろな大きさの学習が意外にぱっと出てこないから仕方ないね。
ときどき学習させるとエラーが肥大化していって、最後はdoubleがNaNになって死ぬことがあって、
これが最後まで改善できませんでした:<。
今回はカラーコードのIndexを出力できればいいので、
oneHotを導入することで学習がアバウトでも動作するようにしてみました。
oneHotなしだと途中で学習が停滞してしまうことが多くて、たぶんニューロンが少ないんだろうなと思ってるけど詳細は不明。
そのままでは処理が遅すぎてどうしようもないと思ったので、適当に最適化してみたのがこちら。
[ソースコード]
最適化の方針としては、
・Matrixを二次元配列から一次元配列にしてキャッシュに乗りやすく。これは参考サイトさんほぼそのままです。
・行列の乗算時のアドレス計算を、ポインタを使用して掛け算をできるだけ消しました。乗除算は基本的に重いので繰り返し処理の内側ではできるだけ減らしたい。
・行列の乗算を、計算順序を変えてキャッシュに乗りやすいらしい順序に変更。
・transpose処理いらなくない?
と思って専用の乗算処理を用意してみました。乗算処理内でアドレス計算を縦横入れ替えています。
・行列用のメモリを確保するの重いので、メモリが足りていればメモリ確保しないようにして一時変数として使いまわすようにしています。
最終的には既存のライブラリを使うほうが早いし汎用性もあるということになるので、深入りはやめました。
GPU使うなり、マルチスレッドを使うなりあると思います。
参考にしたのは
10.1: Introduction to Neural Networks - The Nature of Code https://www.youtube.com/watch?v=XJ7HLz9VYz0
C++ neural networks from scratch - Pt 1. building a matrix library https://www.lyndonduong.com/linalg-cpp/
まずは作ってみようと思って作ったのがこちら。
[ソースコード]
#include <cstdio>
#include <cmath>
#include <vector>
#include <random>
#include <future>
#include <iostream>
#include <fstream>
#include <string>
class Matrix
{
public:
static Matrix matmul( const Matrix& a, const Matrix& b )
{
Matrix ret( a.m_rows, b.m_cols );
if ( a.m_cols == b.m_rows )
{
for ( int y = 0; y < ret.m_rows; y++ )
{
for ( int x = 0; x < ret.m_cols; x++ )
{
double sum = 0;
for ( int z = 0; z < a.m_cols; ++z )
{
sum += a.m_values[y][z] * b.m_values[z][x];
}
ret.m_values[y][x] = sum;
}
}
}
else
{
std::printf("%s - miss match matrix.[%dx%d]x[%dx%d]\n", __FUNCSIG__, a.m_rows, a.m_cols, b.m_rows, b.m_cols );
}
return ret;
}
static Matrix sub( const Matrix& a, const Matrix& b )
{
Matrix ret( a.m_rows, a.m_cols );
if ( a.m_cols == b.m_cols &&
a.m_rows == b.m_rows )
{
for ( int y = 0; y < ret.m_rows; y++ )
{
for ( int x = 0; x < ret.m_cols; x++ )
{
ret.m_values[y][x] = a.m_values[y][x] - b.m_values[y][x];
}
}
}
return ret;
}
static Matrix createFromArray( const std::vector<double>& array )
{
Matrix ret( array.size(), 1 );
for ( int i = 0; i<array.size(); ++i )
{
ret.m_values[i][0] = array[i];
}
return ret;
}
static Matrix transpose( const Matrix& m )
{
Matrix ret( m.m_cols, m.m_rows );
for ( int y = 0; y < ret.m_rows; ++y )
{
for ( int x = 0; x < ret.m_cols; ++x )
{
ret.m_values[y][x] = m.m_values[x][y];
}
}
return ret;
}
public:
Matrix( int rows, int cols )
: m_rows( rows )
, m_cols( cols )
{
m_values.resize( rows );
for ( auto& vec : m_values )
{
vec.resize( cols );
}
}
Matrix( const Matrix& m )
: m_rows( m.m_rows )
, m_cols( m.m_cols )
, m_values( m.m_values )
{
}
Matrix& operator = ( const Matrix& m )
{
m_values = m.m_values;
m_rows = m.m_rows;
m_cols = m.m_cols;
return *this;
}
double& getValue( int x, int y )
{
return m_values[y][x];
}
const double& getValue( int x, int y ) const
{
return m_values[y][x];
}
void randomizeN()
{
std::random_device rndDev;
std::mt19937 random( rndDev() );
std::uniform_real_distribution<double> dist( 0, 1.0 / std::sqrt( static_cast<double>(size()) ) );
for ( auto& v : m_values )
{
for ( auto& d : v )
{
d = dist( random );
}
}
}
void multiplyElementwise( const Matrix& m )
{
for ( int y = 0; y < m_rows; ++y )
{
for ( int x = 0; x < m_cols; ++x )
{
m_values[y][x] *= m.m_values[y][x];
}
}
}
void multiplyScalar( double n )
{
for ( auto& r : m_values )
{
for ( auto& c : r )
{
c *= n;
}
}
}
void add( double n )
{
for ( auto& r : m_values )
{
for ( auto& c : r )
{
c += n;
}
}
}
void add( const Matrix& m )
{
if ( m_rows != m.m_rows || m_cols != m.m_cols ) return;
for ( int y = 0; y < m_rows; ++y )
{
for ( int x = 0; x < m_cols; ++x )
{
m_values[y][x] += m.m_values[y][x];
}
}
}
Matrix& operator + ( const Matrix& m )
{
add( m );
return *this;
}
void map( std::function<double(const double&)> fn )
{
for ( int y = 0; y < m_rows; ++y )
{
for ( int x = 0; x < m_cols; ++x )
{
m_values[y][x] = fn( m_values[y][x] );
}
}
}
void print()
{
std::printf("%s - rows: %d, cols: %d\n", __FUNCSIG__, m_rows, m_cols );
for ( int y = 0; y < m_values.size(); ++y )
{
for ( int x = 0; x < m_values[y].size(); ++x )
{
std::printf("%f, ", m_values[y][x]);
}
std::printf( "\n" );
}
}
int size() const
{
return m_rows * m_cols;
}
int m_rows;
int m_cols;
std::vector<std::vector<double>> m_values;
};
class NeuralNetwork
{
public:
static double sigmoid( const double& d )
{
return 1.0 / (1.0 + std::exp( -d ));
}
static double leaklyRelu( const double& d )
{
return std::max( d * 0.01, d );
//return std::min( std::max( d * 0.01, d ), 6.0 );
}
static double dsigmoid( const double& d )
{
//const double s = sigmoid( d );
//return s * (1 - s);
return d * (1.0 - d);
}
static double dleaklyRelu( const double& d )
{
return (d >= 0.0) ? 1.0 : 0.01;
}
static double tanh( const double& d )
{
return std::tanh( d );
}
static double dtanh( const double& d )
{
return 1.0 - std::pow( std::tanh( d ), 2.0 );
}
public:
NeuralNetwork( int input, int hidden, int output )
{
create( input, hidden, output );
}
void create( int input, int hidden, int output )
{
m_weights.push_back( Matrix( hidden, input ) );
m_weights.push_back( Matrix( output, hidden ) );
for ( auto& m : m_weights )
{
m.randomizeN();
}
m_bias.push_back( Matrix( hidden, 1 ) );
m_bias.push_back( Matrix( output, 1 ) );
for ( auto& m : m_bias )
{
m.randomizeN();
}
m_output.resize( m_bias.size(), Matrix(output, 1) );
}
Matrix foward_prop( const Matrix& input )
{
Matrix m = input;
for ( int i = 0; i < m_weights.size(); ++i )
{
m = Matrix::matmul( m_weights[i], m ) + m_bias[i];
m.map( leaklyRelu );
m_output[i] = m;
}
// 最後の奴だけoneHotしてみる
oneHot( m );
m_output.back() = m;
return m;
}
void step( Matrix& m )
{
for ( int y = 0; y < m.m_rows; ++y )
{
for ( int x = 0; x < m.m_cols; ++x )
{
m.getValue( x, y ) = m.getValue( x, y ) > 0.5 ? 1 : 0;
}
}
}
void oneHot( Matrix& m )
{
int mostTopX = -1;
int mostTopY = -1;
double mostTopValue = -100;
for ( int y = 0; y < m.m_rows; ++y )
{
for ( int x = 0; x < m.m_cols; ++x )
{
double& d = m.getValue( x, y );
if ( d > mostTopValue )
{
mostTopValue = d;
mostTopX = x;
mostTopY = y;
}
d = 0;
}
}
if ( mostTopX >= 0 && mostTopX < m.m_cols &&
mostTopY >= 0 && mostTopY < m.m_rows )
{
m.getValue( mostTopX, mostTopY ) = 1;
}
else
{
std::printf("%s - err. couldnt find most top idx\n", __FUNCSIG__);
}
}
// [参考]part4
void train( const std::vector<std::pair<Matrix, Matrix>>& trainingDataList, double l_rate, int epoch )
{
// 学習をランダムにしてみる
auto trainingDataListShuffle = trainingDataList;
std::random_device randDev;
std::mt19937 randMt( randDev() );
for ( int e = 0; e < epoch; ++e )
{
// 学習順序をランダムに
std::shuffle( trainingDataListShuffle.begin(), trainingDataListShuffle.end(), randMt );
double sumError = 0;
for ( auto& trainingData : trainingDataListShuffle )
{
// forward
Matrix m = foward_prop( trainingData.first );
// error
{
Matrix em = Matrix::sub( trainingData.second, m );
em.map( []( const double& d ) -> double { return d * d; } );
for ( int k = 0; k < em.m_rows; ++k )
{
sumError += em.getValue( 0, k );
}
}
// training
{
Matrix err = Matrix::sub( trainingData.second, m_output.back() );
for ( int i=m_weights.size()-1; i>=0; i--)
{
const Matrix tsWeight = Matrix::transpose( m_weights[i] );
Matrix prevError = Matrix::matmul( tsWeight, err ); //< 前のレイヤー(次の処理)へ渡すerr
Matrix dOutput = m_output[i];
dOutput.map( dleaklyRelu );
Matrix gradients = err;
gradients.multiplyElementwise( dOutput );
gradients.multiplyScalar( l_rate );
const Matrix tsOutput = Matrix::transpose( i>0 ? m_output[i-1] : trainingData.first );
const Matrix weightGrad = Matrix::matmul( gradients, tsOutput );
m_bias[i].add( gradients );
m_weights[i].add( weightGrad );
err = prevError;
}
}
}
std::printf("[%d] %f\n", e, sumError);
}
}
void print()
{
std::printf( "%s\n", __FUNCSIG__ );
std::printf( "weights\n" );
for ( int i = 0; i < m_weights.size(); ++i )
{
const Matrix& m = m_weights[i];
for ( int y = 0; y < m.m_rows; ++y )
{
for ( int x = 0; x < m.m_cols; ++x )
{
std::printf( "[layer:%d][%d][%d]%f\n", i, y, x, m.getValue(x,y) );
}
}
}
std::printf( "bias\n" );
for ( int i = 0; i < m_bias.size(); ++i )
{
const Matrix& m = m_bias[i];
for ( int y = 0; y < m.m_rows; ++y )
{
for ( int x = 0; x < m.m_cols; ++x )
{
std::printf( "[layer:%d][%d][%d]%f\n", i, y, x, m.getValue( x, y ) );
}
}
}
}
bool saveWeights( char* fileName ) const
{
std::ofstream outputFile( fileName );
if ( outputFile.is_open() )
{
// save weights
for ( auto& wm : m_weights )
{
for ( int y = 0; y < wm.m_rows; ++y )
{
for ( int x = 0; x < wm.m_cols; ++x )
{
auto weightStr = std::to_string( wm.getValue( x, y ) );
outputFile << weightStr << ",";
}
}
}
// save bias
for ( auto& bm : m_bias )
{
for ( int y = 0; y < bm.m_rows; ++y )
{
for ( int x = 0; x < bm.m_cols; ++x )
{
auto weightStr = std::to_string( bm.getValue( x, y ) );
outputFile << weightStr << ",";
}
}
}
outputFile.close();
return true;
}
return false;
}
bool loadWeights( char* fileName )
{
if ( fileName )
{
std::vector<double> weightsList;
// read weights file
{
std::ifstream inputFile( fileName );
if ( inputFile.is_open() )
{
std::string str;
while ( std::getline( inputFile, str, ',' ) )
{
double d = std::stod( str );
weightsList.push_back( d );
}
}
inputFile.close();
}
if ( weightsList.empty() ) return false;
// update weights
int idx = 0;
for ( auto& wm : m_weights )
{
for ( int y = 0; y < wm.m_rows; ++y )
{
for ( int x = 0; x < wm.m_cols; ++x )
{
if ( weightsList.size() <= idx ) return false;
wm.getValue( x, y ) = weightsList[idx];
idx++;
}
}
}
// update bias
for ( auto& bm : m_bias )
{
for ( int y = 0; y < bm.m_rows; ++y )
{
for ( int x = 0; x < bm.m_cols; ++x )
{
if ( weightsList.size() <= idx ) return false;
bm.getValue( x, y ) = weightsList[idx];
idx++;
}
}
}
return true;
}
return false;
}
//private:
public:
std::vector<Matrix> m_weights;
std::vector<Matrix> m_bias;
std::vector<Matrix> m_output;
};
// [参考]http://www.htmq.com/color/colorname.shtml
// 138 color
struct OriginalColorData
{
double r, g, b;
char* name;
} g_originalColorData[] = {
{ 255, 255, 255, "white" },
{ 245,245,245, "whitesmoke" },
{ 248,248,255, "ghostwhite" },
{ 240,248,255, "aliceblue" },
{ 230,230,250, "lavender" },
{ 240,255,255, "azure" },
{ 224,255,255, "lightcyan" },
{ 245,255,250, "mintcream" },
{ 240,255,240, "honeydew" },
{ 255,255,240, "ivory" },
{ 245,245,220, "beige" },
{ 255,255,224, "lightyellow" },
{ 250,250,210, "lightgoldenrodyellow" },
{ 255,250,205, "lemonchiffon" },
{ 255,250,240, "floralwhite" },
{ 253,245,230, "oldlace" },
{ 255,248,220, "cornsilk" },
{ 255,239,213, "papayawhite" },
{ 255,235,205, "blanchedalmond" },
{ 255,228,196, "bisque" },
{ 255,250,250, "snow" },
{ 250,240,230, "linen" },
{ 250,235,215, "antiquewhite" },
{ 255,245,238, "seashell" },
{ 255,240,245, "lavenderblush" },
{ 255,228,225, "mistyrose" },
{ 220,220,220, "gainsboro" },
{ 211,211,211, "lightgray" },
{ 176,196,222, "lightsteelblue" },
{ 173,216,230, "lightblue" },
{ 135,206,250, "lightskyblue" },
{ 176,224,230, "powderblue" },
{ 175,238,238, "paleturquoise" },
{ 135,206,235, "skyblue" },
{ 102,205,170, "mediumaquamarine" },
{ 127,255,212, "aquamarine" },
{ 152,251,152, "palegreen" },
{ 144,238,144, "lightgreen" },
{ 240,230,140, "khaki" },
{ 238,232,170, "palegoldenrod" },
{ 255,228,181, "moccasin" },
{ 255,222,173, "navajowhite" },
{ 255,218,185, "peachpuff" },
{ 245,222,179, "wheat" },
{ 255,192,203, "pink" },
{ 255,182,193, "lightpink" },
{ 216,191,216, "thistle" },
{ 221,160,221, "plum" },
{ 192,192,192, "silver" },
{ 169,169,169, "darkgray" },
{ 119,136,153, "lightslategray" },
{ 112,128,144, "slategray" },
{ 106,90,205, "slateblue" },
{ 70,130,180, "steelblue" },
{ 123,104,238, "mediumslateblue" },
{ 65,105,225, "royalblue" },
{ 0,0,255, "blue" },
{ 30,144,255, "dodgerblue" },
{ 100,149,237, "cornflowerblue" },
{ 0,191,255, "deepskyblue" },
{ 0,255,255, "cyan(aqua)" },
{ 64,224,208, "turquoise" },
{ 72,209,204, "mediumturquoise" },
{ 0,206,209, "darkturquoise" },
{ 32,178,170, "lightseagreen" },
{ 0,250,154, "mediumspringgreen" },
{ 0,255,127, "springgreen" },
{ 0,255,0, "lime" },
{ 50,205,50, "limegreen" },
{ 154,205,50, "yellowgreen" },
{ 124,252,0, "lawngreen" },
{ 127,255,0, "chartreuse" },
{ 173,255,47, "greenyellow" },
{ 255,255,0, "yellow" },
{ 255,215,0, "gold" },
{ 255,165,0, "orange" },
{ 255,140,0, "darkorange" },
{ 218,165,32, "goldenrod" },
{ 222,184,135, "burlywood" },
{ 210,180,140, "tan" },
{ 244,164,96, "sandybrown" },
{ 233,150,122, "darksalmon" },
{ 240,128,128, "lightcoral" },
{ 250,128,114, "salmon" },
{ 255,160,122, "lightsalmon" },
{ 255,127,80, "coral" },
{ 255,99,71, "tomato" },
{ 255,69,0, "orangered" },
{ 255,0,0, "red" },
{ 255,20,147, "deeppink" },
{ 255,105,180, "hotpink" },
{ 219,112,147, "palevioletred" },
{ 238,130,238, "violet" },
{ 218,112,214, "orchid" },
{ 255,0,255, "magenta(fuchsia)" },
{ 186,85,211, "mediumorchid" },
{ 153,50,204, "darkorchid" },
{ 148,0,211, "darkviolet" },
{ 138,43,226, "blueviolet" },
{ 147,112,219, "mediumpurple" },
{ 128,128,128, "gray" },
{ 0,0,205, "mediumblue" },
{ 0,139,139, "darkcyan" },
{ 95,158,160, "cadetblue" },
{ 143,188,143, "darkseagreen" },
{ 60,179,113, "mediumseagreen" },
{ 0,128,128, "teal" },
{ 34,139,34, "forestgreen" },
{ 46,139,87, "seagreen" },
{ 189,183,107, "darkkhaki" },
{ 205,133,63, "peru" },
{ 220,20,60, "crimson" },
{ 205,92,92, "indianred" },
{ 188,143,143, "rosybrown" },
{ 199,21,133, "mediumvioletred" },
{ 105,105,105, "dimgray" },
{ 0,0,0, "black" },
{ 25,25,112, "midnightblue" },
{ 72,61,139, "darkslateblue" },
{ 0,0,139, "darkblue" },
{ 0,0,128, "navy" },
{ 47,79,79, "darkslategray" },
{ 0,128,0, "green" },
{ 0,100,0, "darkgreen" },
{ 85,107,47, "darkolivegreen" },
{ 107,142,35, "olivedrab" },
{ 128,128,0, "olive" },
{ 184,134,11, "darkgoldenrod" },
{ 210,105,30, "chocolate" },
{ 160,82,45, "sienna" },
{ 139,69,19, "saddlebrown" },
{ 178,34,34, "firebrick" },
{ 165,42,42, "brown" },
{ 128,0,0, "maroon" },
{ 139,0,0, "darkred" },
{ 139,0,139, "darkmagenta" },
{ 128,0,128, "purple" },
{ 75,0,130, "indigo" },
};
static void normalizeColors()
{
for ( auto& data : g_originalColorData )
{
data.r /= 255;
data.g /= 255;
data.b /= 255;
}
}
static std::vector<std::pair<Matrix, Matrix>> createTrainingDataList()
{
std::vector< std::pair<Matrix, Matrix> > ret;
for ( int i = 0; i < _countof( g_originalColorData ); ++i )
{
// input
std::pair<Matrix, Matrix> data( Matrix( 1, 1 ), Matrix( 1, 1 ) );
data.first = Matrix::createFromArray( std::vector<double>( { g_originalColorData[i].r, g_originalColorData[i].g, g_originalColorData[i].b } ) );
// output
std::vector<double> tmp( _countof( g_originalColorData ) );
tmp[i] = 1;
data.second = Matrix::createFromArray( tmp );
ret.push_back( data );
}
return ret;
}
static int getMostTopIdx( const Matrix& nnOutputs )
{
int mostTopRateIdx = -1;
double mostTopRate = 0;
for ( int i = 0; i < nnOutputs.m_rows; ++i )
{
auto value = nnOutputs.getValue( 0, i );
if ( value > mostTopRate )
{
mostTopRate = value;
mostTopRateIdx = i;
}
}
return mostTopRateIdx;
}
int main()
{
normalizeColors();
NeuralNetwork nn( 3, _countof(g_originalColorData), _countof( g_originalColorData ) );
nn.loadWeights( "weights.txt" );
const auto trainingDataList = createTrainingDataList();
for (;;)
{
nn.train( trainingDataList, 0.05, 5000 );
for ( auto& data : trainingDataList )
{
auto output = nn.foward_prop( data.first );
const int idx = getMostTopIdx( output );
if ( idx >= 0 && idx < _countof( g_originalColorData ) )
{
const int r = static_cast<int>(g_originalColorData[idx].r * 255);
const int g = static_cast<int>(g_originalColorData[idx].g * 255);
const int b = static_cast<int>(g_originalColorData[idx].b * 255);
const int r2 = data.first.getValue( 0, 0 ) * 255;
const int g2 = data.first.getValue( 0, 1 ) * 255;
const int b2 = data.first.getValue( 0, 2 ) * 255;
std::printf( "answer is %d,%d,%d, %s ( correct: %d, %d, %d )\n", r, g, b, g_originalColorData[idx].name, r2, g2, b2 );
}
else
{
std::printf( "idx error\n" );
}
}
nn.saveWeights( "weights.txt" );
system( "PAUSE" );
}
return 0;
}
ちょっと前に作ったjavascript版のニューラルネットワークと同様に、
HTMLカラーコードを学習させることにしました。
xor以外で手ごろな大きさの学習が意外にぱっと出てこないから仕方ないね。
ときどき学習させるとエラーが肥大化していって、最後はdoubleがNaNになって死ぬことがあって、
これが最後まで改善できませんでした:<。
今回はカラーコードのIndexを出力できればいいので、
oneHotを導入することで学習がアバウトでも動作するようにしてみました。
oneHotなしだと途中で学習が停滞してしまうことが多くて、たぶんニューロンが少ないんだろうなと思ってるけど詳細は不明。
そのままでは処理が遅すぎてどうしようもないと思ったので、適当に最適化してみたのがこちら。
[ソースコード]
#include <cstdio>
#include <cmath>
#include <vector>
#include <random>
#include <future>
#include <iostream>
#include <fstream>
#include <string>
class Matrix
{
public:
static Matrix matmul( const Matrix& a, const Matrix& b )
{
Matrix ret( a.m_rows, b.m_cols );
matmul( ret, a, b );
return ret;
}
// outputとa,bが同じアドレスだとうまく動作しない
static void matmul( Matrix& output, const Matrix& a, const Matrix& b )
{
if ( a.m_cols == b.m_rows )
{
output.resize( a.m_rows, b.m_cols );
output.zero();
double* pOutStart = output.m_values.data();
const double* pAStart = a.m_values.data();
const double* pBStart = b.m_values.data();
const int addOutY = output.m_cols;
const int addAY = a.m_cols;
const int addBY = b.m_cols;
const int yMax = output.m_rows;
const int xMax = output.m_cols;
const int zMax = a.m_cols;
for ( int y = 0; y < yMax; y++ )
{
const double* pA = pAStart;
const double* pBStart2 = pBStart;
for ( int z = 0; z < zMax; ++z )
{
double* pOut = pOutStart;
const double* pB = pBStart2;
for ( int x = 0; x < xMax; x++ )
{
*pOut += *pA * *pB;
pOut++;
pB++;
}
pA++;
pBStart2 += addBY;
}
pOutStart += addOutY;
pAStart += addAY;
}
}
else
{
std::printf( "%s - miss match matrix.[%dx%d]x[%dx%d]\n", __FUNCSIG__, a.m_rows, a.m_cols, b.m_rows, b.m_cols );
}
}
// outputとa,bが同じアドレスだとうまく動作しない
// a=normal, b=transposeにして乗算
static void matmul_nt( Matrix& out, const Matrix& a, const Matrix& b )
{
const int b_rows = b.m_cols;
const int b_cols = b.m_rows;
if ( a.m_cols == b_rows )
{
out.resize( a.m_rows, b_cols );
out.zero();
double* pOutStart = out.m_values.data();
const double* pAStart = a.m_values.data();
const double* pBStart = b.m_values.data();
const int addOutY = out.m_cols;
const int addAY = a.m_cols;
const int addBY = b.m_cols;
const int yMax = out.m_rows;
const int xMax = out.m_cols;
const int zMax = a.m_cols;
for ( int y = 0; y < yMax; y++ )
{
const double* pA = pAStart;
const double* pBStart2 = pBStart;
for ( int z = 0; z < zMax; ++z )
{
double* pOut = pOutStart;
const double* pB = pBStart2;
for ( int x = 0; x < xMax; x++ )
{
*pOut += *pA * *pB;
pOut++;
pB+=addBY;
}
pA++;
pBStart2++;
}
pOutStart += addOutY;
pAStart += addAY;
}
}
else
{
std::printf( "%s - miss match matrix.[%dx%d]x[%dx%d]\n", __FUNCSIG__, a.m_rows, a.m_cols, b.m_rows, b.m_cols );
}
}
// outputとa,bが同じアドレスだとうまく動作しない
// a=transpose, b=normalにして乗算
static void matmul_tn( Matrix& out, const Matrix& a, const Matrix& b )
{
const int a_rows = a.m_cols;
const int a_cols = a.m_rows;
if ( a_cols == b.m_rows )
{
out.resize( a_rows, b.m_cols );
out.zero();
double* pOutStart = out.m_values.data();
const double* pAStart = a.m_values.data();
const double* pBStart = b.m_values.data();
const int addOutY = out.m_cols;
const int addAY = a.m_cols;
const int addBY = b.m_cols;
const int yMax = out.m_rows;
const int xMax = out.m_cols;
const int zMax = a_cols;
for ( int y = 0; y < yMax; y++ )
{
const double* pA = pAStart;
const double* pBStart2 = pBStart;
for ( int z = 0; z < zMax; ++z )
{
double* pOut = pOutStart;
const double* pB = pBStart2;
for ( int x = 0; x < xMax; x++ )
{
*pOut += *pA * *pB;
pOut++;
pB += addBY;
}
pA += addAY;
pBStart2++;
}
pOutStart += addOutY;
pAStart++;
}
}
else
{
std::printf( "%s - miss match matrix.[%dx%d]x[%dx%d]\n", __FUNCSIG__, a.m_rows, a.m_cols, b.m_rows, b.m_cols );
}
}
#if 0
static Matrix sub( const Matrix& a, const Matrix& b )
{
Matrix ret( a.m_rows, a.m_cols );
if ( a.m_cols == b.m_cols &&
a.m_rows == b.m_rows )
{
double* pOut = ret.m_values.data();
const double* pA = a.m_values.data();
const double* pB = b.m_values.data();
const int n = ret.size();
for ( int i = 0; i < n; ++i )
{
*pOut = *pA - *pB;
pOut++;
pA++;
pB++;
}
}
else
{
std::printf("%s - not same size[%d,%d]-[%d,%d]\n", __FUNCSIG__, a.m_rows, a.m_cols, b.m_rows, b.m_cols );
}
return ret;
}
#endif
static void sub( Matrix& out, const Matrix& a, const Matrix& b )
{
if ( a.m_cols == b.m_cols &&
a.m_rows == b.m_rows )
{
out.resize( a.m_rows, a.m_cols );
double* pOut = out.m_values.data();
const double* pA = a.m_values.data();
const double* pB = b.m_values.data();
const int n = out.size();
for ( int i = 0; i < n; ++i )
{
*pOut = *pA - *pB;
pOut++;
pA++;
pB++;
}
}
else
{
std::printf( "%s - not same size[%d,%d]-[%d,%d]\n", __FUNCSIG__, a.m_rows, a.m_cols, b.m_rows, b.m_cols );
}
}
static Matrix createFromArray( const std::vector<double>& array )
{
Matrix ret( array.size(), 1 );
const double* pArray = array.data();
const int arraySize = array.size();
for ( int i = 0; i < arraySize; ++i )
{
ret.getValue(0,i) = *pArray;
pArray++;
}
return ret;
}
// 使ってないけど一応残しておく
static Matrix transpose( const Matrix& m )
{
Matrix ret( m.m_cols, m.m_rows );
double* pOutStart = ret.m_values.data();
const double* pInStart = m.m_values.data();
const int addOutY = ret.m_cols;
const int addInY = m.m_cols;
for ( int y = 0; y < ret.m_rows; ++y )
{
double* pOut = pOutStart;
const double* pIn = pInStart;
for ( int x = 0; x < ret.m_cols; ++x )
{
*pOut = *pIn;
pOut++;
pIn += addInY;
}
pOutStart += addOutY;
pInStart++;;
}
return ret;
}
public:
Matrix( int rows, int cols )
: m_rows( rows )
, m_cols( cols )
{
m_values.resize( rows * cols );
}
Matrix( const Matrix& m )
: m_rows( m.m_rows )
, m_cols( m.m_cols )
, m_values( m.m_values )
{
}
Matrix& operator = ( const Matrix& m )
{
resize( m.m_rows, m.m_cols );
memcpy( m_values.data(), m.m_values.data(), m.size() * sizeof( double ) );
return *this;
}
void resize( int rows, int cols )
{
if ( m_rows != rows ||
m_cols != cols )
{
if ( m_values.size() < rows * cols )
{
m_values.resize( rows * cols );
}
m_rows = rows;
m_cols = cols;
}
}
double& getValue( int x, int y )
{
return m_values[y * m_cols + x];
}
const double& getValue( int x, int y ) const
{
return m_values[y * m_cols + x];
}
void randomizeN()
{
std::random_device rndDev;
std::mt19937 random( rndDev() );
//std::mt19937 random( 0 );
std::uniform_real_distribution<double> dist( 0, 1.0 / std::sqrt(static_cast<double>(size())) );
for ( auto& v : m_values )
{
v = dist( random );
}
}
void multiplyElementwise( const Matrix& m )
{
if ( m_rows != m.m_rows || m_cols != m.m_cols )
{
std::printf( "%s - not same size[%d,%d]-[%d,%d]\n", __FUNCSIG__, m_rows, m_cols, m.m_rows, m.m_cols );
return;
}
double* pOut = m_values.data();
const double* pIn = m.m_values.data();
const int n = size();
for ( int i = 0; i < n; ++i )
{
*pOut *= *pIn;
pOut++;
pIn++;
}
}
void multiplyScalar( double d )
{
double* pOut = m_values.data();
int n = size();
for ( int i = 0; i < n; ++i )
{
*pOut *= d;
pOut++;
}
}
void add( double d )
{
double* pOut = m_values.data();
int n = size();
for ( int i = 0; i < n; ++i )
{
*pOut += d;
pOut++;
}
}
void add( const Matrix& m )
{
if ( m_rows != m.m_rows || m_cols != m.m_cols )
{
std::printf( "%s - not same size[%d,%d]-[%d,%d]\n", __FUNCSIG__, m_rows, m_cols, m.m_rows, m.m_cols );
return;
}
double* pOut = m_values.data();
const double* pIn = m.m_values.data();
int n = size();
for ( int i = 0; i < n; ++i )
{
*pOut += *pIn;
pOut++;
pIn++;
}
}
Matrix& operator + ( const Matrix& m )
{
add( m );
return *this;
}
void map( std::function<double( const double& )> fn )
{
double* pOut = m_values.data();
const int n = size();
for ( int i = 0; i < n; ++i )
{
*pOut = fn( *pOut );
pOut++;
}
}
void print() const
{
std::printf( "%s - rows: %d, cols: %d\n", __FUNCSIG__, m_rows, m_cols );
for ( int y = 0; y < m_rows; ++y )
{
for ( int x = 0; x < m_cols; ++x )
{
std::printf( "%f, ", getValue(x,y) );
}
std::printf( "\n" );
}
}
void zero()
{
memset( m_values.data(), 0, m_values.size() * sizeof( double ) );
}
int size() const
{
return m_rows * m_cols;
}
int m_rows;
int m_cols;
std::vector<double> m_values;
};
class NeuralNetwork
{
public:
static double sigmoid( const double& d )
{
return 1.0 / (1.0 + std::exp( -d ));
}
static double leaklyRelu( const double& d )
{
return std::max( d * 0.01, d );
//return std::min( std::max( d * 0.01, d ), 6.0 );
}
static double dsigmoid( const double& d )
{
//const double s = sigmoid( d );
//return s * (1 - s);
return d * (1.0 - d);
}
static double dleaklyRelu( const double& d )
{
return (d >= 0.0) ? 1.0 : 0.01;
}
static double tanh( const double& d )
{
return std::tanh( d );
}
static double dtanh( const double& d )
{
return 1.0 - std::pow( std::tanh( d ), 2.0 );
}
public:
NeuralNetwork( int input, int hidden, int output )
{
create( input, hidden, output );
}
NeuralNetwork( int input, int hidden, int hidden2, int output )
{
create( input, hidden, hidden2, output );
}
void create( int input, int hidden, int output )
{
m_weights.push_back( Matrix( hidden, input ) );
m_weights.push_back( Matrix( output, hidden ) );
for ( auto& m : m_weights )
{
m.randomizeN();
}
m_bias.push_back( Matrix( hidden, 1 ) );
m_bias.push_back( Matrix( output, 1 ) );
for ( auto& m : m_bias )
{
m.randomizeN();
}
m_output.resize( m_bias.size(), Matrix(output, 1) );
}
void create( int input, int hidden, int hidden2, int output )
{
m_weights.push_back( Matrix( hidden, input ) );
m_weights.push_back( Matrix( hidden2, hidden ) );
m_weights.push_back( Matrix( output, hidden2 ) );
for ( auto& m : m_weights )
{
m.randomizeN();
}
m_bias.push_back( Matrix( hidden, 1 ) );
m_bias.push_back( Matrix( hidden2, 1 ) );
m_bias.push_back( Matrix( output, 1 ) );
for ( auto& m : m_bias )
{
m.randomizeN();
}
m_output.resize( m_bias.size(), Matrix( output, 1 ) );
}
Matrix foward_prop( const Matrix& input )
{
Matrix* pM = const_cast<Matrix*>(&input);
Matrix* pOut = m_output.data();
Matrix* pWeights = m_weights.data();
Matrix* pBias = m_bias.data();
const int n = m_weights.size();
for ( int i = 0; i < n; ++i )
{
Matrix::matmul( *pOut, *pWeights, *pM );
pOut->add( *pBias );
pOut->map( leaklyRelu );
pM = pOut;
pOut++;
pWeights++;
pBias++;
}
oneHot( *pM );
return *pM;
}
void step( Matrix& m )
{
for ( int i = 0; i < m.size(); ++i )
{
m.m_values[i] = m.m_values[i] > 0.5 ? 1 : 0;
}
}
void oneHot( Matrix& m )
{
int mostTopIdx = -1;
double mostTopValue = -DBL_MIN;
for ( int i = 0; i < m.size(); ++i )
{
double& d = m.m_values[i];
if ( d > mostTopValue )
{
mostTopValue = d;
mostTopIdx = i;
}
d = 0;
}
if ( mostTopIdx >= 0 && mostTopIdx < m.size() )
{
m.m_values[mostTopIdx] = 1;
}
else
{
std::printf("%s - err. couldnt find most top idx\n", __FUNCSIG__);
}
}
// [参考]part4
void train( const std::vector<std::pair<Matrix, Matrix>>& trainingDataList, double l_rate, int epoch )
{
// メモリ確保を防ぐために外にだしておいて、メモリ確保回数を最小限にしてみる
Matrix dOutput( 1, 1 );
Matrix prevError( 1, 1 );
Matrix gradients( 1, 1 );
Matrix weightGrad( 1, 1 );
Matrix err( 1, 1 );
// 学習をランダムにしてみる
auto trainingDataListShuffle = trainingDataList;
std::random_device randDev;
std::mt19937 randMt( randDev() );
//std::mt19937 randMt( 0 );
for ( int e = 0; e < epoch; ++e )
{
std::shuffle( trainingDataListShuffle.begin(), trainingDataListShuffle.end(), randMt );
double sumError = 0;
for ( auto& trainingData : trainingDataListShuffle )
{
// forward
foward_prop( trainingData.first );
// calc error
Matrix::sub( err, trainingData.second, m_output.back() );
// sumError
for ( int i = 0; i < err.m_rows; ++i )
{
const float d = err.getValue( 0, i );
sumError += d * d;
}
// training
for ( int i=m_weights.size()-1; i>=0; i--)
{
Matrix::matmul_tn( prevError, m_weights[i], err ); //< 前のレイヤー(次の処理)へ渡すerr
dOutput = m_output[i];
dOutput.map( dleaklyRelu );
/*
Matrix& gradients = err; //< これが地味に重い。わかりやすくするために名前だけ変えておきたかったが
gradients.multiplyElementwise( dOutput );
gradients.multiplyScalar( l_rate );
Matrix::matmul_nt( weightGrad, gradients, i > 0 ? m_output[i - 1] : trainingData.first );
m_bias[i].add( gradients );
m_weights[i].add( weightGrad );
*/
err.multiplyElementwise( dOutput );
err.multiplyScalar( l_rate );
Matrix::matmul_nt( weightGrad, err, i > 0 ? m_output[i - 1] : trainingData.first );
m_bias[i].add( err );
m_weights[i].add( weightGrad );
err = prevError;
}
}
std::printf("[%d] %f\n", e, sumError);
}
}
void print()
{
std::printf( "%s\n", __FUNCSIG__ );
std::printf( "weights\n" );
for ( int i = 0; i < m_weights.size(); ++i )
{
const Matrix& m = m_weights[i];
for ( int y = 0; y < m.m_rows; ++y )
{
for ( int x = 0; x < m.m_cols; ++x )
{
std::printf( "[layer:%d][%d][%d]%f\n", i, y, x, m.getValue(x,y) );
}
}
}
std::printf( "bias\n" );
for ( int i = 0; i < m_bias.size(); ++i )
{
const Matrix& m = m_bias[i];
for ( int y = 0; y < m.m_rows; ++y )
{
for ( int x = 0; x < m.m_cols; ++x )
{
std::printf( "[layer:%d][%d][%d]%f\n", i, y, x, m.getValue(x,y) );
}
}
}
}
bool saveWeights( char* fileName ) const
{
std::ofstream outputFile( fileName );
if ( outputFile.is_open() )
{
// save weights
for ( auto& m : m_weights )
{
for ( auto& d : m.m_values )
{
auto weightStr = std::to_string( d );
outputFile << weightStr << ",";
}
}
// save bias
for ( auto& m : m_bias )
{
for ( auto& d : m.m_values )
{
auto weightStr = std::to_string( d );
outputFile << weightStr << ",";
}
}
outputFile.close();
return true;
}
return false;
}
bool loadWeights( char* fileName )
{
if ( fileName )
{
std::vector<double> weightsList;
// read weights file
{
std::ifstream inputFile( fileName );
if ( inputFile.is_open() )
{
std::string str;
while ( std::getline( inputFile, str, ',' ) )
{
double d = std::stod( str );
weightsList.push_back( d );
}
}
inputFile.close();
}
if ( weightsList.empty() ) return false;
// update weights
int idx = 0;
for ( auto& m : m_weights )
{
for ( auto& d : m.m_values )
{
if ( weightsList.size() <= idx ) break;
d = weightsList[idx++];
}
}
// update bias
for ( auto& m : m_bias )
{
for ( auto& d : m.m_values )
{
if ( weightsList.size() <= idx ) break;
d = weightsList[idx++];
}
}
return true;
}
return false;
}
//private:
public:
std::vector<Matrix> m_weights;
std::vector<Matrix> m_bias;
std::vector<Matrix> m_output;
};
// [参考]http://www.htmq.com/color/colorname.shtml
// 140 color
struct OriginalColorData
{
double r, g, b;
char* name;
} g_originalColorData[] = {
{ 255, 255, 255, "white" },
{ 245,245,245, "whitesmoke" },
{ 248,248,255, "ghostwhite" },
{ 240,248,255, "aliceblue" },
{ 230,230,250, "lavender" },
{ 240,255,255, "azure" },
{ 224,255,255, "lightcyan" },
{ 245,255,250, "mintcream" },
{ 240,255,240, "honeydew" },
{ 255,255,240, "ivory" },
{ 245,245,220, "beige" },
{ 255,255,224, "lightyellow" },
{ 250,250,210, "lightgoldenrodyellow" },
{ 255,250,205, "lemonchiffon" },
{ 255,250,240, "floralwhite" },
{ 253,245,230, "oldlace" },
{ 255,248,220, "cornsilk" },
{ 255,239,213, "papayawhite" },
{ 255,235,205, "blanchedalmond" },
{ 255,228,196, "bisque" },
{ 255,250,250, "snow" },
{ 250,240,230, "linen" },
{ 250,235,215, "antiquewhite" },
{ 255,245,238, "seashell" },
{ 255,240,245, "lavenderblush" },
{ 255,228,225, "mistyrose" },
{ 220,220,220, "gainsboro" },
{ 211,211,211, "lightgray" },
{ 176,196,222, "lightsteelblue" },
{ 173,216,230, "lightblue" },
{ 135,206,250, "lightskyblue" },
{ 176,224,230, "powderblue" },
{ 175,238,238, "paleturquoise" },
{ 135,206,235, "skyblue" },
{ 102,205,170, "mediumaquamarine" },
{ 127,255,212, "aquamarine" },
{ 152,251,152, "palegreen" },
{ 144,238,144, "lightgreen" },
{ 240,230,140, "khaki" },
{ 238,232,170, "palegoldenrod" },
{ 255,228,181, "moccasin" },
{ 255,222,173, "navajowhite" },
{ 255,218,185, "peachpuff" },
{ 245,222,179, "wheat" },
{ 255,192,203, "pink" },
{ 255,182,193, "lightpink" },
{ 216,191,216, "thistle" },
{ 221,160,221, "plum" },
{ 192,192,192, "silver" },
{ 169,169,169, "darkgray" },
{ 119,136,153, "lightslategray" },
{ 112,128,144, "slategray" },
{ 106,90,205, "slateblue" },
//*
{ 70,130,180, "steelblue" },
{ 123,104,238, "mediumslateblue" },
{ 65,105,225, "royalblue" },
{ 0,0,255, "blue" },
{ 30,144,255, "dodgerblue" },
{ 100,149,237, "cornflowerblue" },
{ 0,191,255, "deepskyblue" },
{ 0,255,255, "cyan(aqua)" },
{ 64,224,208, "turquoise" },
{ 72,209,204, "mediumturquoise" },
{ 0,206,209, "darkturquoise" },
{ 32,178,170, "lightseagreen" },
{ 0,250,154, "mediumspringgreen" },
{ 0,255,127, "springgreen" },
{ 0,255,0, "lime" },
{ 50,205,50, "limegreen" },
{ 154,205,50, "yellowgreen" },
{ 124,252,0, "lawngreen" },
{ 127,255,0, "chartreuse" },
{ 173,255,47, "greenyellow" },
{ 255,255,0, "yellow" },
{ 255,215,0, "gold" },
{ 255,165,0, "orange" },
{ 255,140,0, "darkorange" },
{ 218,165,32, "goldenrod" },
{ 222,184,135, "burlywood" },
{ 210,180,140, "tan" },
{ 244,164,96, "sandybrown" },
{ 233,150,122, "darksalmon" },
{ 240,128,128, "lightcoral" },
{ 250,128,114, "salmon" },
{ 255,160,122, "lightsalmon" },
{ 255,127,80, "coral" },
{ 255,99,71, "tomato" },
{ 255,69,0, "orangered" },
{ 255,0,0, "red" },
{ 255,20,147, "deeppink" },
{ 255,105,180, "hotpink" },
{ 219,112,147, "palevioletred" },
{ 238,130,238, "violet" },
{ 218,112,214, "orchid" },
{ 255,0,255, "magenta(fuchsia)" },
{ 186,85,211, "mediumorchid" },
{ 153,50,204, "darkorchid" },
{ 148,0,211, "darkviolet" },
{ 138,43,226, "blueviolet" },
{ 147,112,219, "mediumpurple" },
{ 128,128,128, "gray" },
{ 0,0,205, "mediumblue" },
{ 0,139,139, "darkcyan" },
{ 95,158,160, "cadetblue" },
{ 143,188,143, "darkseagreen" },
{ 60,179,113, "mediumseagreen" },
{ 0,128,128, "teal" },
{ 34,139,34, "forestgreen" },
{ 46,139,87, "seagreen" },
{ 189,183,107, "darkkhaki" },
{ 205,133,63, "peru" },
{ 220,20,60, "crimson" },
{ 205,92,92, "indianred" },
{ 188,143,143, "rosybrown" },
{ 199,21,133, "mediumvioletred" },
{ 105,105,105, "dimgray" },
{ 0,0,0, "black" },
{ 25,25,112, "midnightblue" },
{ 72,61,139, "darkslateblue" },
{ 0,0,139, "darkblue" },
{ 0,0,128, "navy" },
{ 47,79,79, "darkslategray" },
{ 0,128,0, "green" },
{ 0,100,0, "darkgreen" },
{ 85,107,47, "darkolivegreen" },
{ 107,142,35, "olivedrab" },
{ 128,128,0, "olive" },
{ 184,134,11, "darkgoldenrod" },
{ 210,105,30, "chocolate" },
{ 160,82,45, "sienna" },
{ 139,69,19, "saddlebrown" },
{ 178,34,34, "firebrick" },
{ 165,42,42, "brown" },
{ 128,0,0, "maroon" },
{ 139,0,0, "darkred" },
{ 139,0,139, "darkmagenta" },
{ 128,0,128, "purple" },
{ 75,0,130, "indigo" },
//*/
};
static void normalizeColors()
{
for ( auto& data : g_originalColorData )
{
data.r /= 255;
data.g /= 255;
data.b /= 255;
}
}
static std::vector<std::pair<Matrix, Matrix>> createTrainingDataList()
{
std::vector< std::pair<Matrix, Matrix> > ret;
for ( int i = 0; i < _countof( g_originalColorData ); ++i )
{
// input
std::pair<Matrix, Matrix> data( Matrix( 1, 1 ), Matrix( 1, 1 ) );
data.first = Matrix::createFromArray( std::vector<double>( { g_originalColorData[i].r, g_originalColorData[i].g, g_originalColorData[i].b } ) );
// output
std::vector<double> tmp( _countof( g_originalColorData ) );
tmp[i] = 1;
data.second = Matrix::createFromArray( tmp );
ret.push_back( data );
}
return ret;
}
static int getMostTopIdx( const Matrix& nnOutputs )
{
int mostTopRateIdx = -1;
double mostTopRate = 0;
for ( int i = 0; i < nnOutputs.m_rows; ++i )
{
//auto value = nnOutputs.m_values[i][0];
auto value = nnOutputs.getValue( 0, i );
if ( value > mostTopRate )
{
mostTopRate = value;
mostTopRateIdx = i;
}
}
return mostTopRateIdx;
}
int main()
{
normalizeColors();
NeuralNetwork nn( 3, _countof(g_originalColorData), _countof( g_originalColorData ) );
nn.loadWeights( "weights.txt" );
const auto trainingDataList = createTrainingDataList();
for (;;)
{
nn.train( trainingDataList, 0.05, 5000 );
for ( auto& data : trainingDataList )
{
auto output = nn.foward_prop( data.first );
//output.print();
const int idx = getMostTopIdx( output );
if ( idx >= 0 && idx < _countof( g_originalColorData ) )
{
const int r = static_cast<int>(g_originalColorData[idx].r * 255);
const int g = static_cast<int>(g_originalColorData[idx].g * 255);
const int b = static_cast<int>(g_originalColorData[idx].b * 255);
const int r2 = data.first.getValue( 0, 0 ) * 255;
const int g2 = data.first.getValue( 0, 1 ) * 255;
const int b2 = data.first.getValue( 0, 2 ) * 255;
std::printf( "answer is %d,%d,%d, %s ( correct: %d, %d, %d )\n", r, g, b, g_originalColorData[idx].name, r2, g2, b2 );
}
else
{
std::printf( "idx error\n" );
}
}
//nn.print();
nn.saveWeights( "weights.txt" );
system( "PAUSE" );
}
return 0;
}
最適化の方針としては、
・Matrixを二次元配列から一次元配列にしてキャッシュに乗りやすく。これは参考サイトさんほぼそのままです。
・行列の乗算時のアドレス計算を、ポインタを使用して掛け算をできるだけ消しました。乗除算は基本的に重いので繰り返し処理の内側ではできるだけ減らしたい。
・行列の乗算を、計算順序を変えてキャッシュに乗りやすいらしい順序に変更。
static Matrix matmul( const Matrix& a, const Matrix& b )
{
Matrix ret( a.m_rows, b.m_cols );
if ( a.m_cols == b.m_rows )
{
for ( int y = 0; y < ret.m_rows; y++ )
{
for ( int z = 0; z < a.m_cols; ++z )
{
for ( int x = 0; x < ret.m_cols; x++ )
{
ret.getValue( x, y ) += a.getValue( z, y ) * b.getValue( x, z );
}
}
}
}
return ret;
}
zとxの順番が逆に。これをポインタでぐちゃぐちゃにしたのが上のになります。実際に動作させてみると確かにちょっと早くなった。・transpose処理いらなくない?
と思って専用の乗算処理を用意してみました。乗算処理内でアドレス計算を縦横入れ替えています。
・行列用のメモリを確保するの重いので、メモリが足りていればメモリ確保しないようにして一時変数として使いまわすようにしています。
最終的には既存のライブラリを使うほうが早いし汎用性もあるということになるので、深入りはやめました。
GPU使うなり、マルチスレッドを使うなりあると思います。
登録:
コメント (Atom)







