シェルスクリプトマガジン

test

特別レポート(Vol.76掲載)

投稿日:2022.01.25 | カテゴリー: コード

著者:松浦智之

2021年6月2~4日に技術カンファレンス「ソフトウェア・シンポジウム 2021 in 大分」がオンラインで開催されました。筆者が所属するユニバーサル・シェル・プログラミング研究所は、そのカンファレンスに二つの論文を投稿しました。その中で最優秀発表賞に選ばれた「UNIX機におけるIoT機器制御のためのタイミング管理」を紹介します。

シェルスクリプトマガジン Vol.76は以下のリンク先でご購入できます。

図2 シェルスクリプト(Accurate_interval.sh)

#!/bin/bash

i=1
yes | valve -l 5s | while read dummy; do
  wget WebサイトのURL/${i}.txt
  [ $i -ge 100 ] && break
  i=$((i+1))
done

Pythonあれこれ(Vol.76掲載)

投稿日:2022.01.25 | カテゴリー: コード

著者:飯尾 淳

本連載では「Pythonを昔から使っているものの、それほど使いこなしてはいない」という筆者が、いろいろな日常業務をPythonで処理することで、立派な「蛇使い」に育つことを目指します。その過程を温かく見守ってください。皆さんと共に勉強していきましょう。第6回は、やや趣向を変えてアルゴリズムを解説します。前半では関数の再帰的定義とその効率化、後半ではソーティングアルゴリズムについて紹介します。

シェルスクリプトマガジン Vol.76は以下のリンク先でご購入できます。

図1 再帰を使わずに階乗を求める関数を定義した例

def factorial(n):
  retvar = 1
  for i in range(n):
    retvar = retvar * i
  return retvar

図4 メモ化アルゴリズムを使って効率化したfib() 関数の定義例

memo = [0] * 100
memo[0] = memo[1] = 1
def fib(n):
  if memo[n-1] == 0: memo[n-1] = fib(n-1)
  if memo[n-2] == 0: memo[n-2] = fib(n-2)
  if memo[n] == 0: memo[n] = memo[n-1] + memo[n-2]
  return memo[n]

図7 バブルソートを実施する関数の実装例

def bubble_sort(x):
  y = x[:]
  for i in range(len(y)-1):
    for j in range(len(y)-1,i,-1):
      if y[j-1] > y[j]:
        tmp = y[j-1]; y[j-1] = y[j]; y[j] = tmp
    print(y)
  return y

図9 マージソートを実施する関数の実装例

def merge_sort(x):
  retary = []
  if len(x) <= 1:
    retary.extend(x)
  else:
    m = len(x) // 2
    first = merge_sort(x[:m])
    second = merge_sort(x[m:])
    while len(first) > 0 and len(second) > 0:
      retary.append(first.pop(0) \
        if first[0] < second[0] else second.pop(0))
    retary.extend(first if len(first) > 0 else second)
  return retary

図11 ヒープソートを実施する関数の実装例

from heapq import heappush, heappop
 
def heap_sort(x):
  retary = []
  heap = []
  for i in x: heappush(heap, i)
  while len(heap) > 0: retary.append(heappop(heap))
  return retary

機械学習ことはじめ(Vol.76掲載)

投稿日:2022.01.25 | カテゴリー: コード

著者:川嶋 宏彰

本連載では、機械学習の基礎となるさまざまな手法の仕組みや、それらの手法のPythonでの利用方法を解説していきます。今回は、複数のモデルを束ねて用いるアンサンブル学習について解説します。

シェルスクリプトマガジン Vol.76は以下のリンク先でご購入できます。

図2 データセットの読み込みから、散布図のプロットまでを実施するPythonコード

import seaborn as sns
import matplotlib.pyplot as plt

plt.rcParams['font.size'] = 14
penguins = sns.load_dataset('penguins')
# 取り出す特徴量
features = ['bill_depth_mm', 'body_mass_g']  # (★)
# features = ['bill_depth_mm', 'bill_length_mm']  # 取り出す特徴量を変える
# 対象とするペンギン種
target_species = ['Adelie', 'Gentoo']  # (★)
# target_species = ['Adelie', 'Chinstrap', 'Gentoo']  # 3種のペンギンにする
# 今回用いる特徴量をクラスラベルと共に取り出す
df = penguins[['species'] + features].copy()
df.dropna(inplace=True)  # NaN が含まれる行は削除
# 今回用いるペンギン種のみとする
df2 = df[df['species'].isin(target_species)].copy()
print(df2.shape)  # (274, 3) と表示される
# 現在のパレットから用いる種 (target_species) に合わせたパレットを作成
palette = {c: sns.color_palette()[k] for k, c
           in enumerate(df['species'].unique()) if c in target_species}
plt.figure(figsize=(5, 5))
sns.scatterplot(data=df2, x=features[0], y=features[1],
                hue='species', palette=palette)
plt.show()
X = df2[features].values   # 各個体の2次元特徴量(行数=個体数)
y = df2['species'].values  # 各個体のクラスラベル

図3 決定木による2クラス分類をするPythonコード

import matplotlib as mpl
import numpy as np
from sklearn.tree import DecisionTreeClassifier, export_text, plot_tree

def plot_decision_boundary(X, y, clf, xylabels=None, palette=None, fig=None, ngrid=50):
  """ 分類器 clf の決定境界を描画 """
  if fig is None: fig = plt.figure(figsize=(5, 5))
  else: plt.figure(fig.number)
  # 2次元空間にグリッド点を準備
  xmin = X.min(axis=0)  # 各列の最小値
  xmax = X.max(axis=0)  # 各列の最大値
  xstep = [(xmax[j]-xmin[j]) / ngrid for j in range(2)]  # グリッドのステップ幅
  xmin = [xmin[j] - 8*xstep[j] for j in range(2)]  # 少し広めに
  xmax = [xmax[j] + 8*xstep[j] for j in range(2)]
  aranges = [np.arange(xmin[j], xmax[j] + xstep[j], xstep[j]) for j in range(2)]
  x0grid, x1grid = np.meshgrid(*aranges)
  # 各グリッド点でクラスを判定
  y_pred = clf.predict(np.c_[x0grid.ravel(), x1grid.ravel()])
  y_pred = y_pred.reshape(x0grid.shape)  # 2次元に
  y_pred = np.searchsorted(np.unique(y_pred), y_pred)  # 値をインデックスに
  clist = palette.values() if type(palette) is dict else palette
  cmap = mpl.colors.ListedColormap(clist) if palette is not None else None
  plt.contourf(x0grid, x1grid, y_pred, alpha=0.3, cmap=cmap)
  sns.scatterplot(x=X[:, 0], y=X[:, 1], hue=y, palette=palette)
  plt.legend()
  plt.xlim([xmin[0], xmax[0]])
  plt.ylim([xmin[1], xmax[1]])
  if xylabels is not None:
    plt.xlabel(xylabels[0])
    plt.ylabel(xylabels[1])
  return fig
# 決定木
max_depth = 2  #(★)木の深さ
clf_dt = DecisionTreeClassifier(max_depth=max_depth)
clf_dt.fit(X, y)  # 学習
# 決定境界を可視化
plot_decision_boundary(X, y, clf_dt, features, palette)
plt.show()
# 決定木をテキストで表示
tree_text = export_text(clf_dt)
print(tree_text)
# 木の可視化
plt.figure(figsize=(10, 8))
plot_tree(clf_dt, class_names=target_species, feature_names=features)
plt.show()

図13 アンサンブル学習された決定木の表示用関数を定義するPythonコード

from sklearn.base import is_classifier

def plot_trees_and_boundaries(clf, X, y):
  # 決定境界を可視化
  plot_decision_boundary(X, y, clf, features, palette)
  plt.show()
  # 各ベースモデル(決定木)を表示
  for i, clf_dt in enumerate(clf.estimators_[:3]):
    print('-' * 10, i, '-' * 10)
    plt.figure(figsize=(10, 8))
    plot_tree(clf_dt, class_names=target_species, feature_names=features)
    plt.show()
    if is_classifier(clf_dt):  # 分類木ならば決定境界を可視化            
      plot_decision_boundary(X, y, clf_dt, features, palette)
      plt.show()

図14 ランダムフォレストによる分類器の学習をするPythonコード

from sklearn.ensemble import RandomForestClassifier

clf_rf = RandomForestClassifier(n_estimators=100, random_state=1)
clf_rf.fit(X, y)
plot_trees_and_boundaries(clf_rf, X, y)

図16 構成モデルに決定木を用いたバギングをするPythonコード

from sklearn.ensemble import BaggingClassifier

clf_bag = BaggingClassifier(DecisionTreeClassifier(),
                            n_estimators=100, random_state=1)
clf_bag.fit(X, y)

図18 構成モデルに決定木を用いたアダブーストをするPythonコード

from sklearn.ensemble import AdaBoostClassifier

clf_ada = AdaBoostClassifier(DecisionTreeClassifier(max_depth=2),
                             n_estimators=100)
clf_ada.fit(X, y)
plot_trees_and_boundaries(clf_ada, X, y)

図20 構成モデル(回帰木)の数を変えながら勾配ブースティングをするPythonコード

from sklearn.ensemble import GradientBoostingClassifier

for m in [2, 4, 10, 20, 50]:
  clf_gbdt = GradientBoostingClassifier(n_estimators=m)
  clf_gbdt.fit(X, y)  # 学習
  plot_decision_boundary(X, y, clf_gbdt, features, palette)
  plt.title(f'GradientBoosting m = {m}')
  plt.show()

図22 XGBoost による学習をするPythonコード

from xgboost import XGBClassifier

# クラスラベルを整数0、1、2に変換
y_int = df2['species'].map({'Adelie': 0, 'Chinstrap': 1, 'Gentoo': 2}).values
clf_xgb = XGBClassifier(use_label_encoder=False, eval_metric='mlogloss')
clf_xgb.fit(X, y_int)
plot_decision_boundary(X, y, clf_xgb, features, palette)
plt.show()

Raspberry Piを100%活用しよう(Vol.76掲載)

投稿日:2022.01.25 | カテゴリー: コード

著者:米田 聡

小型コンピュータボード「Raspberry Pi」(ラズパイ)向けにさまざまな拡張ボードが発売されています。その拡張ボードとラズパイを組み合わせれば、ラズパイでいろいろなことが簡単に試せます。第9回は、人感センサーを搭載する拡張基板を扱います。

シェルスクリプトマガジン Vol.76は以下のリンク先でご購入できます。

図3 焦電赤外線センサ拡張基板のサンプルプログラム(ADRSZPY.py)

import RPi.GPIO as GPIO
import time

IR_PORT=5

GPIO.setmode(GPIO.BCM)
GPIO.setup(IR_PORT, GPIO.IN)

try:
    while True:
        if GPIO.input(IR_PORT) == GPIO.HIGH:
            print("There is human")
        else:
            print("Nothing")
        
        time.sleep(1)


except KeyboardInterrupt:
        pass

GPIO.cleanup()

特集1 Linuxカーネルの仕組み(Vol.76記載)

投稿日:2022.01.25 | カテゴリー: コード

著者:平田 豊

LinuxというOSの中核となるのが「Linuxカーネル」というソフトウエアです。Linuxカーネルの動作を理解するには、ソースコードを追いかける必要があります。しかし、いきなりソースコードを読んでもよく分からないものです。本特集記事では、学習の「入り口」となるように、学習用の環境を構築する方法を紹介します。また、Linuxカーネルの一部の機能をピックアップして、その実装について解説します。本特集をきっかけにLinuxカーネルのソースコード読解を始めましょう。

シェルスクリプトマガジン Vol.76は以下のリンク先でご購入できます。

図1 OS レスプログラムのイメージ

for (;;) {
    // スイッチが押された
    if (isSwitchOn()) {
        // 要因クリア
        ClearSwitch();
        // LED点灯
        TurnOnLED();
    }
    // スイッチが離された
    if (isSwitchOff()) {
        // 要因クリア
        ClearSwitch();
        // LED点灯
        TurnOffLED();
    }
    // ディレー
    delay();
}

図7 QEMU の起動用シェルスクリプト

#!/bin/sh

BUILD_PATH="${HOME}/buildroot-2021.08.1"
IMAGE_DIR="${BUILD_PATH}/output/images"
exec qemu-system-aarch64 \
    -M virt \
    -cpu cortex-a53 \
    -nographic \
    -smp 2 \
    -m 512 \
    -kernel ${IMAGE_DIR}/Image \
    -append "rootwait root=/dev/vda console=ttyAMA0" \
    -drive file=${IMAGE_DIR}/rootfs.ext4,if=none,format=raw,id=hd0 \
    -device virtio-blk-device,drive=hd0 \
    -netdev user,id=eth0 \
    -device virtio-net-device,netdev=eth0 \
    -object rng-random,filename=/dev/urandom,id=rng0 \
    -device virtio-rng-pci,rng=rng0

図8 Linux カーネルに追加するコード

(略)
static int run_init_process(const char *init_filename)
{
        const char *const *p;
    printk("hoge 0x%016lx (%zu)\n", jiffies, sizeof(jiffies));
        argv_init[0] = init_filename;
(略)

図11 init デーモンを起動する箇所のソースコード

if (!try_to_run_init_process("/sbin/init") ||
    !try_to_run_init_process("/etc/init") ||
    !try_to_run_init_process("/bin/init") ||
    !try_to_run_init_process("/bin/sh"))
    return 0;

panic("No working init found.  Try passing init= option to kernel. "
      "See Linux Documentation/admin-guide/init.rst for guidance.");

図12 buildroot 環境のC ライブラリにおけるsyscall 関数の実装

ENTRY (syscall)
    uxtw    x8, w0
    mov x0, x1
    mov x1, x2
    mov x2, x3
    mov x3, x4
    mov x4, x5
    mov x5, x6
    mov x6, x7
    svc 0x0
    cmn x0, #4095
    b.cs    1f
    RET

図13 システムコールに対応する関数を呼び出すためのマクロ定義の例

#define __SYSCALL_DEFINEx(x, name, ...)                     \
(略)
    asmlinkage long __arm64_sys##name(const struct pt_regs *regs)       \
    {                                   \
        return __se_sys##name(SC_ARM64_REGS_TO_ARGS(x,__VA_ARGS__));    \
    }                                   \
(略)
    static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))

図14 machine_halt() 関数のコード

void machine_halt(void)
{
    local_irq_disable();
    smp_send_stop();
    while (1);
}

図15 machine_power_off() 関数のコード

void machine_power_off(void)
{
    local_irq_disable();
    smp_send_stop();
    if (pm_power_off)
        pm_power_off();
}

図17 schedule() 関数のコード

asmlinkage __visible void __sched schedule(void)
{
    struct task_struct *tsk = current;

    sched_submit_work(tsk);
    do {
        preempt_disable();
        __schedule(false);
        sched_preempt_enable_no_resched();
    } while (need_resched());
    sched_update_worker(tsk);
}
EXPORT_SYMBOL(schedule);

図18 FIFO からのデータを出力するプログラムのコード

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char **argv){
  int i, fd = -1;
  ssize_t sz;
  char *filename, buf[64];
  if (argc == 1) {
    printf("Usage: %s fifo\n", argv[0]);
    exit(1);
  }
  filename = argv[1];
  fd = open(filename, O_RDWR);
  if (fd == -1) {
    perror("open");
    goto error;
  }
  sz = read(fd, buf, sizeof(buf));
  if (sz == -1) {
    perror("read");
    goto error;
  }
  for (i = 0 ; i < sz ; i++) {
    printf("%02x ", buf[i]);
  }
  printf("\n");

error:
  if (fd != -1) close(fd);
}

図19 wait_event_interruptible_exclusive() 関数のマクロ定義

#define __wait_event_interruptible_exclusive(wq, condition)         \
    ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 1, 0,          \
              schedule())

#define wait_event_interruptible_exclusive(wq, condition)           \
({                                      \
    int __ret = 0;                              \
    might_sleep();                              \
    if (!(condition))                           \
        __ret = __wait_event_interruptible_exclusive(wq, condition);    \
    __ret;                                  \
})

図20 msleep() 関数のコード

void msleep(unsigned int msecs)
{
    unsigned long timeout = msecs_to_jiffies(msecs) + 1;

    while (timeout)
        timeout = schedule_timeout_uninterruptible(timeout);
}

図21 process_timeout() 関数とschedule_timeout() 関数のコード

static void process_timeout(struct timer_list *t)
{
    struct process_timer *timeout = from_timer(timeout, t, timer);

    wake_up_process(timeout->task);
}
(略)
signed long __sched schedule_timeout(signed long timeout)
{
(略)
    expire = timeout + jiffies;

    timer.task = current;
    timer_setup_on_stack(&timer.timer, process_timeout, 0);
    __mod_timer(&timer.timer, expire, MOD_TIMER_NOTPENDING);
    schedule();
(略)
}

図22 mutex_lock() 関数のコード

void __sched mutex_lock(struct mutex *lock)
{
    might_sleep();

    if (!__mutex_trylock_fast(lock))
        __mutex_lock_slowpath(lock);
}

図23 preempt_enable() 関数のマクロ定義

#ifdef CONFIG_PREEMPTION
#define preempt_enable() \
do { \
    barrier(); \
    if (unlikely(preempt_count_dec_and_test())) \
        __preempt_schedule(); \
} while (0)
#else /* !CONFIG_PREEMPTION */
#define preempt_enable() \
do { \
    barrier(); \
    preempt_count_dec(); \
} while (0) 

図24 ヘッダーファイルでのjiffies 変数の宣言

extern u64 jiffies_64;
extern unsigned long volatile jiffies;

図25 jiffies_64 変数の実体の定義

u64 jiffies_64 = INITIAL_JIFFIES;

図26 INITIAL_JIFFIES 定数の定義

#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))

シェルスクリプトマガジンvol.76 Web掲載記事まとめ

投稿日:2022.01.25 | カテゴリー: コード

004 レポート Visual Studio 2022と.NET 6
005 レポート 超高速リンカー「mold」
008 特集1 Linuxカーネルの仕組み/平田豊 コード掲載
024 特集2 micro:bit v2を使おう/斉暁
034 特集3 国産のGroupSession/大場雄一郎
048 Raspberry Piを100%活用しよう/米田聡  コード掲載
050 機械学習ことはじめ/川嶋宏彰  コード掲載
061 Hello Nogyo!
062 香川大学SLPからお届け!/三枝泰士
066 法林浩之のFIGHTING TALKS/法林浩之
068 タイ語から分かる現地生活/つじみき
072 中小企業手作りIT化奮戦記/菅雄一
076 デジタル庁/桑原滝弥、イケヤシロウ
078 Pythonあれこれ/飯尾淳  コード掲載
084 特別レポート/松浦智之  コード掲載
090 Bash入門/大津真
098 Techパズル/gori.sh
099 コラム「ユニケージ流プロジェクトの初期段階」/シェル魔人

Vol.76

投稿日:2022.01.25 | カテゴリー: バックナンバー

 サーバーOSとして広く利用されているLinux OS。その中核(コア)となるソフトウエアが「Linuxカーネル」です。ちなみに狭い意味でのLinuxは、このカーネルのことを指します。特集1では、Linuxカーネルがオープンソースである点を生かし、ソースコードを見ながら、その仕組みを詳しく解説します。
 特集2では、教育向けマイコンである「BBC micro:bit」のプログラミングを紹介します。BBC micro:bitは、2000円程度で購入でき、小中学生でも扱えるビジュアルプログラミングツールが用意されています。本特集で扱うBBC micro:bit v2は、マイクやスピーカのほか、LEDディスプレイ、各種センサーなどが標準実装されています。BBC micro:bit単体でも十分にプログラミングが楽しめるハードウエアです。
 特集3では、無料でも本格的に利用できるグループウエアソフト「GroupSession」を紹介します。GroupSessionは、スケジュール管理、掲示板、施設予約、ファイル管理、回覧板、日報など、21種類の機能を提供します。日本国内で開発されているので、いずれの機能も日本の企業に適した使い勝手を提供します。
 Vol.76では、シェルスクリプト関連の記事として特別レポートを掲載しました。この特別レポートでは、ソフトウェア・シンポジウム2021 最優秀発表賞を受賞した「UNIX機におけるIoT機器制御のためのタイミング管理」の論文を紹介しています。リアルタイム処理が難しいLinux OSで、ミリ秒レベルでのタイミング制御を実現するコマンドを作成したという面白い内容となっています。
 このほかに、連載「Raspberry Piを100%活用しよう」では、人感センサーを搭載したボードを扱いました。今回も読み応え十分のシェルスクリプトマガジン Vol.76。お見逃しなく!

※記事掲載のコードはこちら。記事の補足情報はこちら

※読者アンケートはこちら

Vol.76 補足情報

投稿日:2022.01.25 | カテゴリー: コード

訂正・補足情報はありません。
情報は随時更新致します。

  • shell-mag ブログの 2022年1月 のアーカイブを表示しています。

  • -->