カタベログ

IT技術に関するブログを書きたい.食べ物関連はInstagramをご参照の事.

リカレントネットワークによる記憶画像の想起

こんばんは.

今日は課題で作ったリカレントネットワークによる記憶画像の想起スクリプトを載せます.画像ファイルはPBM形式のものを扱ってます.課題用なのでかなり課題に特化したものなので,特にファイル操作部分に関しては各自変更が必要でしょう.

import numpy as np
import random as rnd
import copy

def sgn(num):
    return (1 if(num > 0.0) else (0 if(num == 0.0) else -1))

class AssociativeMemory:
    def __init__(self, patternNum=1):
        self.__patternNum = patternNum
        self.__pattern = []

        #ファイル操作
        tmpArray = []
        lineNum = 0
        for line in open('ファイル名','r'):
            if lineNum >= 2:
                line.rstrip('\n')
                for charNum in xrange(len(line)):
                    if ((line[charNum] == "1") or (line[charNum] == "0")):
                        tmpArray.append(1.0 if (int(line[charNum]) == 1) else -1.0)
            lineNum = lineNum + 1
        self.__size = len(tmpArray)
        self.__lena = np.array(tmpArray)
        self.__pattern.append(self.__lena)
        
        #直交する記憶パターンの生成
        for k in xrange(self.__patternNum):
            tmpNDArray = np.zeros(self.__size)
            for i in xrange(self.__size):
                tmpNDArray[i] = (1.0 if(rnd.random() > 0.5) else -1.0)
            self.__pattern.append(tmpNDArray)

        #重みの計算
        self.__weight = np.zeros((self.__size, self.__size))
        for i in xrange(self.__size):
            for j in xrange(i, self.__size):
                if i != j :
                    for p in xrange(len(self.__pattern)):
                        self.__weight[i][j] = self.__weight[i][j] + self.__pattern[p][i] * self.__pattern[p][j]
                    self.__weight[i][j] = self.__weight[i][j] / (self.__size)
                    self.__weight[j][i] = self.__weight[i][j]
                else:
                    self.__weight[i][j] = 0.0
                    self.__weight[j][i] = 0.0
        
    def recall(self, noiseRate = 0.0, step = 15):
        state = copy.deepcopy(self.__lena)
        self.__m = []

        #原画像にノイズを加えてそれを初期状態とする
        for i in xrange(len(state)):
            if noiseRate > 0.0:
                state[i] = (state[i] if(rnd.random() > noiseRate)\
                            else (1.0 if(state[i] == -1)\
                                  else -1.0))
        #初期の誤差を計算
        prodResult = np.dot(state, self.__lena.T)
        self.__m.append(prodResult / (self.__size))
        
        for t in xrange(step):
            nextState = np.zeros(self.__size)

            #想起
            for i in xrange(self.__size):
                prodResult = np.dot(self.__weight[i], state.T)
                nextState[i] = sgn(prodResult)

            #時刻tにおける誤差
            prodResult = np.dot(nextState, self.__lena.T)
            self.__m.append(prodResult / (self.__size))
            state = copy.deepcopy(nextState)

        return self.__m


ドライバはこんな感じ

#!/opt/local/bin/ python
# -*- coding: utf-8 -*-

import AssociativeMemory

test = AssociativeMemory.AssociativeMemory(2)#パターン数を自然数で
print test.recall(0.4)#入力画像として原画像にどれだけノイズを混ぜるかを指定(最高1.0)


こんな感じです.できるだけ計算量を削減させようと工夫したけど,結局,かなり遅いです.重みは対称行列なことを利用したりしたんですが,一番時間かかるのは重みの計算です.見通しを立てて,ループ削減が難しそうならC++でやる方がいいよね.


追記があります.次の記事を参照すると幸せになれます.